mirror of
https://github.com/MaskRay/ccls.git
synced 2025-06-30 03:47:42 +00:00
Reformat to Chromium style.
This commit is contained in:
parent
1b1be28be4
commit
f5314b62b1
@ -1,8 +1,9 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
#include "indexer.h"
|
#include "indexer.h"
|
||||||
#include "platform.h"
|
|
||||||
#include "language_server_api.h"
|
#include "language_server_api.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
|
|
||||||
#include <loguru/loguru.hpp>
|
#include <loguru/loguru.hpp>
|
||||||
|
|
||||||
@ -43,15 +44,15 @@ optional<std::string> LoadCachedFileContents(Config* config,
|
|||||||
return ReadContent(GetCachedBaseFileName(config->cacheDirectory, filename));
|
return ReadContent(GetCachedBaseFileName(config->cacheDirectory, filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteToCache(Config* config,
|
void WriteToCache(Config* config, IndexFile& file) {
|
||||||
IndexFile& file) {
|
|
||||||
if (!config->enableCacheWrite)
|
if (!config->enableCacheWrite)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string cache_basename =
|
std::string cache_basename =
|
||||||
GetCachedBaseFileName(config->cacheDirectory, file.path);
|
GetCachedBaseFileName(config->cacheDirectory, file.path);
|
||||||
|
|
||||||
LOG_IF_S(ERROR, file.file_contents_.empty()) << "Writing " << file.path << " to cache but it has no contents";
|
LOG_IF_S(ERROR, file.file_contents_.empty())
|
||||||
|
<< "Writing " << file.path << " to cache but it has no contents";
|
||||||
|
|
||||||
assert(!file.file_contents_.empty());
|
assert(!file.file_contents_.empty());
|
||||||
std::ofstream cache_content;
|
std::ofstream cache_content;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
struct Config;
|
struct Config;
|
||||||
struct IndexFile;
|
struct IndexFile;
|
||||||
@ -16,5 +16,4 @@ std::unique_ptr<IndexFile> LoadCachedIndex(Config* config,
|
|||||||
optional<std::string> LoadCachedFileContents(Config* config,
|
optional<std::string> LoadCachedFileContents(Config* config,
|
||||||
const std::string& filename);
|
const std::string& filename);
|
||||||
|
|
||||||
void WriteToCache(Config* config,
|
void WriteToCache(Config* config, IndexFile& file);
|
||||||
IndexFile& file);
|
|
@ -15,7 +15,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
#if false
|
#if false
|
||||||
@ -45,34 +44,37 @@ void EmitBacktrace() {
|
|||||||
|
|
||||||
unsigned Flags() {
|
unsigned Flags() {
|
||||||
// TODO: use clang_defaultEditingTranslationUnitOptions()?
|
// TODO: use clang_defaultEditingTranslationUnitOptions()?
|
||||||
return
|
return CXTranslationUnit_Incomplete | CXTranslationUnit_KeepGoing |
|
||||||
CXTranslationUnit_Incomplete |
|
CXTranslationUnit_CacheCompletionResults |
|
||||||
CXTranslationUnit_KeepGoing |
|
CXTranslationUnit_PrecompiledPreamble |
|
||||||
CXTranslationUnit_CacheCompletionResults |
|
CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
|
||||||
CXTranslationUnit_PrecompiledPreamble |
|
|
||||||
CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
// For whatever reason, CreatePreambleOnFirstParse causes clang to become
|
// For whatever reason, CreatePreambleOnFirstParse causes clang to
|
||||||
// very crashy on windows.
|
// become very crashy on windows.
|
||||||
// TODO: do more investigation, submit fixes to clang.
|
// TODO: do more investigation, submit fixes to clang.
|
||||||
| CXTranslationUnit_CreatePreambleOnFirstParse
|
| CXTranslationUnit_CreatePreambleOnFirstParse
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetCompletionPriority(const CXCompletionString& str, CXCursorKind result_kind, const std::string& label) {
|
int GetCompletionPriority(const CXCompletionString& str,
|
||||||
|
CXCursorKind result_kind,
|
||||||
|
const std::string& label) {
|
||||||
int priority = clang_getCompletionPriority(str);
|
int priority = clang_getCompletionPriority(str);
|
||||||
if (result_kind == CXCursor_Destructor) {
|
if (result_kind == CXCursor_Destructor) {
|
||||||
priority *= 100;
|
priority *= 100;
|
||||||
//std::cerr << "Bumping[destructor] " << ls_completion_item.label << std::endl;
|
// std::cerr << "Bumping[destructor] " << ls_completion_item.label <<
|
||||||
|
// std::endl;
|
||||||
}
|
}
|
||||||
if (result_kind == CXCursor_ConversionFunction ||
|
if (result_kind == CXCursor_ConversionFunction ||
|
||||||
(result_kind == CXCursor_CXXMethod && StartsWith(label, "operator"))) {
|
(result_kind == CXCursor_CXXMethod && StartsWith(label, "operator"))) {
|
||||||
//std::cerr << "Bumping[conversion] " << ls_completion_item.label << std::endl;
|
// std::cerr << "Bumping[conversion] " << ls_completion_item.label <<
|
||||||
|
// std::endl;
|
||||||
priority *= 100;
|
priority *= 100;
|
||||||
}
|
}
|
||||||
if (clang_getCompletionAvailability(str) != CXAvailability_Available) {
|
if (clang_getCompletionAvailability(str) != CXAvailability_Available) {
|
||||||
//std::cerr << "Bumping[notavailable] " << ls_completion_item.label << std::endl;
|
// std::cerr << "Bumping[notavailable] " << ls_completion_item.label <<
|
||||||
|
// std::endl;
|
||||||
priority *= 100;
|
priority *= 100;
|
||||||
}
|
}
|
||||||
return priority;
|
return priority;
|
||||||
@ -97,7 +99,6 @@ bool IsCallKind(CXCursorKind kind) {
|
|||||||
|
|
||||||
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
||||||
switch (cursor_kind) {
|
switch (cursor_kind) {
|
||||||
|
|
||||||
case CXCursor_ObjCInstanceMethodDecl:
|
case CXCursor_ObjCInstanceMethodDecl:
|
||||||
case CXCursor_CXXMethod:
|
case CXCursor_CXXMethod:
|
||||||
return lsCompletionItemKind::Method;
|
return lsCompletionItemKind::Method;
|
||||||
@ -146,128 +147,139 @@ lsCompletionItemKind GetCompletionKind(CXCursorKind cursor_kind) {
|
|||||||
case CXCursor_TypeRef:
|
case CXCursor_TypeRef:
|
||||||
return lsCompletionItemKind::Reference;
|
return lsCompletionItemKind::Reference;
|
||||||
|
|
||||||
//return lsCompletionItemKind::Property;
|
// return lsCompletionItemKind::Property;
|
||||||
//return lsCompletionItemKind::Unit;
|
// return lsCompletionItemKind::Unit;
|
||||||
//return lsCompletionItemKind::Value;
|
// return lsCompletionItemKind::Value;
|
||||||
//return lsCompletionItemKind::Keyword;
|
// return lsCompletionItemKind::Keyword;
|
||||||
//return lsCompletionItemKind::Snippet;
|
// return lsCompletionItemKind::Snippet;
|
||||||
//return lsCompletionItemKind::Color;
|
// return lsCompletionItemKind::Color;
|
||||||
//return lsCompletionItemKind::File;
|
// return lsCompletionItemKind::File;
|
||||||
|
|
||||||
case CXCursor_NotImplemented:
|
case CXCursor_NotImplemented:
|
||||||
return lsCompletionItemKind::Text;
|
return lsCompletionItemKind::Text;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr << "[complete] Unhandled completion kind " << cursor_kind << std::endl;
|
std::cerr << "[complete] Unhandled completion kind " << cursor_kind
|
||||||
|
<< std::endl;
|
||||||
return lsCompletionItemKind::Text;
|
return lsCompletionItemKind::Text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildDetailString(CXCompletionString completion_string, std::string& label, std::string& detail, std::string& insert, std::vector<std::string>* parameters) {
|
void BuildDetailString(CXCompletionString completion_string,
|
||||||
|
std::string& label,
|
||||||
|
std::string& detail,
|
||||||
|
std::string& insert,
|
||||||
|
std::vector<std::string>* parameters) {
|
||||||
int num_chunks = clang_getNumCompletionChunks(completion_string);
|
int num_chunks = clang_getNumCompletionChunks(completion_string);
|
||||||
for (int i = 0; i < num_chunks; ++i) {
|
for (int i = 0; i < num_chunks; ++i) {
|
||||||
CXCompletionChunkKind kind = clang_getCompletionChunkKind(completion_string, i);
|
CXCompletionChunkKind kind =
|
||||||
|
clang_getCompletionChunkKind(completion_string, i);
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case CXCompletionChunk_Optional: {
|
case CXCompletionChunk_Optional: {
|
||||||
CXCompletionString nested = clang_getCompletionChunkCompletionString(completion_string, i);
|
CXCompletionString nested =
|
||||||
BuildDetailString(nested, label, detail, insert, parameters);
|
clang_getCompletionChunkCompletionString(completion_string, i);
|
||||||
break;
|
BuildDetailString(nested, label, detail, insert, parameters);
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CXCompletionChunk_Placeholder: {
|
case CXCompletionChunk_Placeholder: {
|
||||||
std::string text = clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
std::string text =
|
||||||
parameters->push_back(text);
|
clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
||||||
detail += text;
|
parameters->push_back(text);
|
||||||
insert += "${" + std::to_string(parameters->size()) + ":" + text + "}";
|
detail += text;
|
||||||
break;
|
insert += "${" + std::to_string(parameters->size()) + ":" + text + "}";
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CXCompletionChunk_CurrentParameter:
|
case CXCompletionChunk_CurrentParameter:
|
||||||
// We have our own parsing logic for active parameter. This doesn't seem
|
// We have our own parsing logic for active parameter. This doesn't seem
|
||||||
// to be very reliable.
|
// to be very reliable.
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CXCompletionChunk_TypedText: {
|
case CXCompletionChunk_TypedText: {
|
||||||
std::string text = clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
std::string text =
|
||||||
label = text;
|
clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
||||||
detail += text;
|
label = text;
|
||||||
insert += text;
|
detail += text;
|
||||||
break;
|
insert += text;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CXCompletionChunk_Text: {
|
case CXCompletionChunk_Text: {
|
||||||
std::string text = clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
std::string text =
|
||||||
detail += text;
|
clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
||||||
insert += text;
|
detail += text;
|
||||||
break;
|
insert += text;
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CXCompletionChunk_Informative: {
|
case CXCompletionChunk_Informative: {
|
||||||
detail += clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
detail +=
|
||||||
break;
|
clang::ToString(clang_getCompletionChunkText(completion_string, i));
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case CXCompletionChunk_ResultType: {
|
case CXCompletionChunk_ResultType: {
|
||||||
CXString text = clang_getCompletionChunkText(completion_string, i);
|
CXString text = clang_getCompletionChunkText(completion_string, i);
|
||||||
std::string new_detail = clang::ToString(text) + detail + " ";
|
std::string new_detail = clang::ToString(text) + detail + " ";
|
||||||
detail = new_detail;
|
detail = new_detail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case CXCompletionChunk_LeftParen:
|
case CXCompletionChunk_LeftParen:
|
||||||
detail += "(";
|
detail += "(";
|
||||||
insert += "(";
|
insert += "(";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_RightParen:
|
case CXCompletionChunk_RightParen:
|
||||||
detail += ")";
|
detail += ")";
|
||||||
insert += ")";
|
insert += ")";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_LeftBracket:
|
case CXCompletionChunk_LeftBracket:
|
||||||
detail += "[";
|
detail += "[";
|
||||||
insert += "[";
|
insert += "[";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_RightBracket:
|
case CXCompletionChunk_RightBracket:
|
||||||
detail += "]";
|
detail += "]";
|
||||||
insert += "]";
|
insert += "]";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_LeftBrace:
|
case CXCompletionChunk_LeftBrace:
|
||||||
detail += "{";
|
detail += "{";
|
||||||
insert += "{";
|
insert += "{";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_RightBrace:
|
case CXCompletionChunk_RightBrace:
|
||||||
detail += "}";
|
detail += "}";
|
||||||
insert += "}";
|
insert += "}";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_LeftAngle:
|
case CXCompletionChunk_LeftAngle:
|
||||||
detail += "<";
|
detail += "<";
|
||||||
insert += "<";
|
insert += "<";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_RightAngle:
|
case CXCompletionChunk_RightAngle:
|
||||||
detail += ">";
|
detail += ">";
|
||||||
insert += ">";
|
insert += ">";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_Comma:
|
case CXCompletionChunk_Comma:
|
||||||
detail += ", ";
|
detail += ", ";
|
||||||
insert += ", ";
|
insert += ", ";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_Colon:
|
case CXCompletionChunk_Colon:
|
||||||
detail += ":";
|
detail += ":";
|
||||||
insert += ":";
|
insert += ":";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_SemiColon:
|
case CXCompletionChunk_SemiColon:
|
||||||
detail += ";";
|
detail += ";";
|
||||||
insert += ";";
|
insert += ";";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_Equal:
|
case CXCompletionChunk_Equal:
|
||||||
detail += "=";
|
detail += "=";
|
||||||
insert += "=";
|
insert += "=";
|
||||||
break;
|
break;
|
||||||
case CXCompletionChunk_HorizontalSpace:
|
case CXCompletionChunk_HorizontalSpace:
|
||||||
case CXCompletionChunk_VerticalSpace:
|
case CXCompletionChunk_VerticalSpace:
|
||||||
detail += " ";
|
detail += " ";
|
||||||
insert += " ";
|
insert += " ";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -285,9 +297,12 @@ void EnsureDocumentParsed(ClangCompleteManager* manager,
|
|||||||
|
|
||||||
std::vector<CXUnsavedFile> unsaved = session->working_files->AsUnsavedFiles();
|
std::vector<CXUnsavedFile> unsaved = session->working_files->AsUnsavedFiles();
|
||||||
|
|
||||||
std::cerr << "[complete] Creating completion session with arguments " << StringJoin(args) << std::endl;
|
std::cerr << "[complete] Creating completion session with arguments "
|
||||||
*tu = MakeUnique<clang::TranslationUnit>(index, session->file.filename, args, unsaved, Flags());
|
<< StringJoin(args) << std::endl;
|
||||||
std::cerr << "[complete] Done creating active; did_fail=" << (*tu)->did_fail << std::endl;
|
*tu = MakeUnique<clang::TranslationUnit>(index, session->file.filename, args,
|
||||||
|
unsaved, Flags());
|
||||||
|
std::cerr << "[complete] Done creating active; did_fail=" << (*tu)->did_fail
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
// Build diagnostics.
|
// Build diagnostics.
|
||||||
if (manager->config_->diagnosticsOnParse && !(*tu)->did_fail) {
|
if (manager->config_->diagnosticsOnParse && !(*tu)->did_fail) {
|
||||||
@ -306,11 +321,14 @@ void EnsureDocumentParsed(ClangCompleteManager* manager,
|
|||||||
void CompletionParseMain(ClangCompleteManager* completion_manager) {
|
void CompletionParseMain(ClangCompleteManager* completion_manager) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Fetching the completion request blocks until we have a request.
|
// Fetching the completion request blocks until we have a request.
|
||||||
ClangCompleteManager::ParseRequest request = completion_manager->parse_requests_.Dequeue();
|
ClangCompleteManager::ParseRequest request =
|
||||||
|
completion_manager->parse_requests_.Dequeue();
|
||||||
|
|
||||||
// If we don't get a session then that means we don't care about the file
|
// If we don't get a session then that means we don't care about the file
|
||||||
// anymore - abandon the request.
|
// anymore - abandon the request.
|
||||||
std::shared_ptr<CompletionSession> session = completion_manager->TryGetSession(request.path, false /*create_if_needed*/);
|
std::shared_ptr<CompletionSession> session =
|
||||||
|
completion_manager->TryGetSession(request.path,
|
||||||
|
false /*create_if_needed*/);
|
||||||
if (!session)
|
if (!session)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -322,24 +340,29 @@ void CompletionParseMain(ClangCompleteManager* completion_manager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<clang::TranslationUnit> parsing;
|
std::unique_ptr<clang::TranslationUnit> parsing;
|
||||||
EnsureDocumentParsed(completion_manager, session, &parsing, &session->index);
|
EnsureDocumentParsed(completion_manager, session, &parsing,
|
||||||
|
&session->index);
|
||||||
|
|
||||||
// Activate new translation unit.
|
// Activate new translation unit.
|
||||||
// tu_last_parsed_at is only read by this thread, so it doesn't need to be under the mutex.
|
// tu_last_parsed_at is only read by this thread, so it doesn't need to be
|
||||||
|
// under the mutex.
|
||||||
session->tu_last_parsed_at = std::chrono::high_resolution_clock::now();
|
session->tu_last_parsed_at = std::chrono::high_resolution_clock::now();
|
||||||
std::lock_guard<std::mutex> lock(session->tu_lock);
|
std::lock_guard<std::mutex> lock(session->tu_lock);
|
||||||
std::cerr << "[completion] Swapping completion session for " << request.path << std::endl;
|
std::cerr << "[completion] Swapping completion session for " << request.path
|
||||||
|
<< std::endl;
|
||||||
session->tu = std::move(parsing);
|
session->tu = std::move(parsing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionDiagnosticsDelayedRefreshMain(ClangCompleteManager* completion_manager) {
|
void CompletionDiagnosticsDelayedRefreshMain(
|
||||||
|
ClangCompleteManager* completion_manager) {
|
||||||
constexpr int kSecondsToWaitForDiagnosticsRefresh = 5;
|
constexpr int kSecondsToWaitForDiagnosticsRefresh = 5;
|
||||||
|
|
||||||
// Refreshes diagnostics a few seconds after the final code completion, since
|
// Refreshes diagnostics a few seconds after the final code completion, since
|
||||||
// we don't get a language server request.
|
// we don't get a language server request.
|
||||||
while (true) {
|
while (true) {
|
||||||
std::unique_lock<std::mutex> l(completion_manager->delayed_diagnostic_wakeup_mtx_);
|
std::unique_lock<std::mutex> l(
|
||||||
|
completion_manager->delayed_diagnostic_wakeup_mtx_);
|
||||||
completion_manager->delayed_diagnostic_wakeup_cv_.wait(l);
|
completion_manager->delayed_diagnostic_wakeup_cv_.wait(l);
|
||||||
|
|
||||||
// Check for spurious wakeup.
|
// Check for spurious wakeup.
|
||||||
@ -350,15 +373,19 @@ void CompletionDiagnosticsDelayedRefreshMain(ClangCompleteManager* completion_ma
|
|||||||
// Get completion request info.
|
// Get completion request info.
|
||||||
if (!l.owns_lock())
|
if (!l.owns_lock())
|
||||||
l.lock();
|
l.lock();
|
||||||
lsTextDocumentPositionParams location = *completion_manager->delayed_diagnostic_last_completion_position_;
|
lsTextDocumentPositionParams location =
|
||||||
|
*completion_manager->delayed_diagnostic_last_completion_position_;
|
||||||
completion_manager->delayed_diagnostic_last_completion_position_.reset();
|
completion_manager->delayed_diagnostic_last_completion_position_.reset();
|
||||||
l.unlock();
|
l.unlock();
|
||||||
|
|
||||||
// Wait five seconds. If there was another completion request, start the
|
// Wait five seconds. If there was another completion request, start the
|
||||||
// waiting process over again.
|
// waiting process over again.
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(kSecondsToWaitForDiagnosticsRefresh));
|
std::this_thread::sleep_for(
|
||||||
|
std::chrono::seconds(kSecondsToWaitForDiagnosticsRefresh));
|
||||||
l.lock();
|
l.lock();
|
||||||
bool has_completion_since_sleeping = completion_manager->delayed_diagnostic_last_completion_position_.has_value();
|
bool has_completion_since_sleeping =
|
||||||
|
completion_manager->delayed_diagnostic_last_completion_position_
|
||||||
|
.has_value();
|
||||||
l.unlock();
|
l.unlock();
|
||||||
if (has_completion_since_sleeping)
|
if (has_completion_since_sleeping)
|
||||||
continue;
|
continue;
|
||||||
@ -376,39 +403,42 @@ void CompletionDiagnosticsDelayedRefreshMain(ClangCompleteManager* completion_ma
|
|||||||
completion_manager->completion_request_.SetIfEmpty(std::move(request));
|
completion_manager->completion_request_.SetIfEmpty(std::move(request));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Fetching the completion request blocks until we have a request.
|
// Fetching the completion request blocks until we have a request.
|
||||||
std::unique_ptr<ClangCompleteManager::CompletionRequest> request = completion_manager->completion_request_.Take();
|
std::unique_ptr<ClangCompleteManager::CompletionRequest> request =
|
||||||
|
completion_manager->completion_request_.Take();
|
||||||
std::string path = request->location.textDocument.uri.GetPath();
|
std::string path = request->location.textDocument.uri.GetPath();
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> session = completion_manager->TryGetSession(path, true /*create_if_needed*/);
|
std::shared_ptr<CompletionSession> session =
|
||||||
|
completion_manager->TryGetSession(path, true /*create_if_needed*/);
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(session->tu_lock);
|
std::lock_guard<std::mutex> lock(session->tu_lock);
|
||||||
EnsureDocumentParsed(completion_manager, session, &session->tu, &session->index);
|
EnsureDocumentParsed(completion_manager, session, &session->tu,
|
||||||
|
&session->index);
|
||||||
|
|
||||||
// Language server is 0-based, clang is 1-based.
|
// Language server is 0-based, clang is 1-based.
|
||||||
unsigned line = request->location.position.line + 1;
|
unsigned line = request->location.position.line + 1;
|
||||||
unsigned column = request->location.position.character + 1;
|
unsigned column = request->location.position.character + 1;
|
||||||
|
|
||||||
std::cerr << "[complete] Completing at " << line << ":" << column << std::endl;
|
std::cerr << "[complete] Completing at " << line << ":" << column
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
std::vector<CXUnsavedFile> unsaved = completion_manager->working_files_->AsUnsavedFiles();
|
std::vector<CXUnsavedFile> unsaved =
|
||||||
|
completion_manager->working_files_->AsUnsavedFiles();
|
||||||
timer.ResetAndPrint("[complete] Fetching unsaved files");
|
timer.ResetAndPrint("[complete] Fetching unsaved files");
|
||||||
|
|
||||||
timer.Reset();
|
timer.Reset();
|
||||||
unsigned const kCompleteOptions = CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments;
|
unsigned const kCompleteOptions =
|
||||||
|
CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments;
|
||||||
CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
|
CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
|
||||||
session->tu->cx_tu,
|
session->tu->cx_tu, session->file.filename.c_str(), line, column,
|
||||||
session->file.filename.c_str(), line, column,
|
unsaved.data(), (unsigned)unsaved.size(), kCompleteOptions);
|
||||||
unsaved.data(), (unsigned)unsaved.size(),
|
|
||||||
kCompleteOptions);
|
|
||||||
if (!cx_results) {
|
if (!cx_results) {
|
||||||
timer.ResetAndPrint("[complete] Code completion failed");
|
timer.ResetAndPrint("[complete] Code completion failed");
|
||||||
if (request->on_complete)
|
if (request->on_complete)
|
||||||
@ -417,7 +447,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timer.ResetAndPrint("[complete] clangCodeCompleteAt");
|
timer.ResetAndPrint("[complete] clangCodeCompleteAt");
|
||||||
std::cerr << "[complete] Got " << cx_results->NumResults << " results" << std::endl;
|
std::cerr << "[complete] Got " << cx_results->NumResults << " results"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (request->on_complete) {
|
if (request->on_complete) {
|
||||||
@ -428,14 +459,15 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
for (unsigned i = 0; i < cx_results->NumResults; ++i) {
|
for (unsigned i = 0; i < cx_results->NumResults; ++i) {
|
||||||
CXCompletionResult& result = cx_results->Results[i];
|
CXCompletionResult& result = cx_results->Results[i];
|
||||||
|
|
||||||
// TODO: Try to figure out how we can hide base method calls without also
|
// TODO: Try to figure out how we can hide base method calls without
|
||||||
// hiding method implementation assistance, ie,
|
// also hiding method implementation assistance, ie,
|
||||||
//
|
//
|
||||||
// void Foo::* {
|
// void Foo::* {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
|
||||||
if (clang_getCompletionAvailability(result.CompletionString) == CXAvailability_NotAvailable)
|
if (clang_getCompletionAvailability(result.CompletionString) ==
|
||||||
|
CXAvailability_NotAvailable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: fill in more data
|
// TODO: fill in more data
|
||||||
@ -443,29 +475,40 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
|
|
||||||
// kind/label/detail/docs/sortText
|
// kind/label/detail/docs/sortText
|
||||||
ls_completion_item.kind = GetCompletionKind(result.CursorKind);
|
ls_completion_item.kind = GetCompletionKind(result.CursorKind);
|
||||||
BuildDetailString(result.CompletionString, ls_completion_item.label, ls_completion_item.detail, ls_completion_item.insertText, &ls_completion_item.parameters_);
|
BuildDetailString(result.CompletionString, ls_completion_item.label,
|
||||||
|
ls_completion_item.detail,
|
||||||
|
ls_completion_item.insertText,
|
||||||
|
&ls_completion_item.parameters_);
|
||||||
ls_completion_item.insertText += "$0";
|
ls_completion_item.insertText += "$0";
|
||||||
ls_completion_item.documentation = clang::ToString(clang_getCompletionBriefComment(result.CompletionString));
|
ls_completion_item.documentation = clang::ToString(
|
||||||
ls_completion_item.sortText = (const char)uint64_t(GetCompletionPriority(result.CompletionString, result.CursorKind, ls_completion_item.label));
|
clang_getCompletionBriefComment(result.CompletionString));
|
||||||
|
ls_completion_item.sortText = (const char)uint64_t(
|
||||||
|
GetCompletionPriority(result.CompletionString, result.CursorKind,
|
||||||
|
ls_completion_item.label));
|
||||||
|
|
||||||
ls_result.push_back(ls_completion_item);
|
ls_result.push_back(ls_completion_item);
|
||||||
}
|
}
|
||||||
timer.ResetAndPrint("[complete] Building " + std::to_string(ls_result.size()) + " completion results");
|
timer.ResetAndPrint("[complete] Building " +
|
||||||
|
std::to_string(ls_result.size()) +
|
||||||
|
" completion results");
|
||||||
|
|
||||||
request->on_complete(ls_result, false /*is_cached_result*/);
|
request->on_complete(ls_result, false /*is_cached_result*/);
|
||||||
timer.ResetAndPrint("[complete] Running user-given completion func");
|
timer.ResetAndPrint("[complete] Running user-given completion func");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completion_manager->config_->diagnosticsOnCodeCompletion) {
|
if (completion_manager->config_->diagnosticsOnCodeCompletion) {
|
||||||
unsigned num_diagnostics = clang_codeCompleteGetNumDiagnostics(cx_results);
|
unsigned num_diagnostics =
|
||||||
|
clang_codeCompleteGetNumDiagnostics(cx_results);
|
||||||
NonElidedVector<lsDiagnostic> ls_diagnostics;
|
NonElidedVector<lsDiagnostic> ls_diagnostics;
|
||||||
for (unsigned i = 0; i < num_diagnostics; ++i) {
|
for (unsigned i = 0; i < num_diagnostics; ++i) {
|
||||||
CXDiagnostic cx_diag = clang_codeCompleteGetDiagnostic(cx_results, i);
|
CXDiagnostic cx_diag = clang_codeCompleteGetDiagnostic(cx_results, i);
|
||||||
optional<lsDiagnostic> diagnostic = BuildAndDisposeDiagnostic(cx_diag, path);
|
optional<lsDiagnostic> diagnostic =
|
||||||
|
BuildAndDisposeDiagnostic(cx_diag, path);
|
||||||
if (diagnostic)
|
if (diagnostic)
|
||||||
ls_diagnostics.push_back(*diagnostic);
|
ls_diagnostics.push_back(*diagnostic);
|
||||||
}
|
}
|
||||||
completion_manager->on_diagnostic_(session->file.filename, ls_diagnostics);
|
completion_manager->on_diagnostic_(session->file.filename,
|
||||||
|
ls_diagnostics);
|
||||||
timer.ResetAndPrint("[complete] Build diagnostics");
|
timer.ResetAndPrint("[complete] Build diagnostics");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,8 +520,10 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
if (completion_manager->config_->diagnosticsOnCodeCompletion &&
|
if (completion_manager->config_->diagnosticsOnCodeCompletion &&
|
||||||
request->is_user_completion) {
|
request->is_user_completion) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(completion_manager->delayed_diagnostic_wakeup_mtx_);
|
std::lock_guard<std::mutex> lock(
|
||||||
completion_manager->delayed_diagnostic_last_completion_position_ = request->location;
|
completion_manager->delayed_diagnostic_wakeup_mtx_);
|
||||||
|
completion_manager->delayed_diagnostic_last_completion_position_ =
|
||||||
|
request->location;
|
||||||
}
|
}
|
||||||
completion_manager->delayed_diagnostic_wakeup_cv_.notify_one();
|
completion_manager->delayed_diagnostic_wakeup_cv_.notify_one();
|
||||||
}
|
}
|
||||||
@ -489,19 +534,25 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CompletionSession::CompletionSession(const Project::Entry& file, WorkingFiles* working_files)
|
CompletionSession::CompletionSession(const Project::Entry& file,
|
||||||
: file(file), working_files(working_files), index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/) {
|
WorkingFiles* working_files)
|
||||||
std::cerr << "[complete] CompletionSession::CompletionSession() for " << file.filename << std::endl;
|
: file(file),
|
||||||
|
working_files(working_files),
|
||||||
|
index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/) {
|
||||||
|
std::cerr << "[complete] CompletionSession::CompletionSession() for "
|
||||||
|
<< file.filename << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionSession::~CompletionSession() {
|
CompletionSession::~CompletionSession() {
|
||||||
std::cerr << "[complete] CompletionSession::~CompletionSession() for " << file.filename << std::endl;
|
std::cerr << "[complete] CompletionSession::~CompletionSession() for "
|
||||||
|
<< file.filename << std::endl;
|
||||||
// EmitBacktrace();
|
// EmitBacktrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
LruSessionCache::LruSessionCache(int max_entries) : max_entries_(max_entries) {}
|
LruSessionCache::LruSessionCache(int max_entries) : max_entries_(max_entries) {}
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> LruSessionCache::TryGetEntry(const std::string& filename) {
|
std::shared_ptr<CompletionSession> LruSessionCache::TryGetEntry(
|
||||||
|
const std::string& filename) {
|
||||||
for (int i = 0; i < entries_.size(); ++i) {
|
for (int i = 0; i < entries_.size(); ++i) {
|
||||||
if (entries_[i]->file.filename == filename)
|
if (entries_[i]->file.filename == filename)
|
||||||
return entries_[i];
|
return entries_[i];
|
||||||
@ -509,7 +560,8 @@ std::shared_ptr<CompletionSession> LruSessionCache::TryGetEntry(const std::strin
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> LruSessionCache::TryTakeEntry(const std::string& filename) {
|
std::shared_ptr<CompletionSession> LruSessionCache::TryTakeEntry(
|
||||||
|
const std::string& filename) {
|
||||||
for (int i = 0; i < entries_.size(); ++i) {
|
for (int i = 0; i < entries_.size(); ++i) {
|
||||||
if (entries_[i]->file.filename == filename) {
|
if (entries_[i]->file.filename == filename) {
|
||||||
std::shared_ptr<CompletionSession> result = entries_[i];
|
std::shared_ptr<CompletionSession> result = entries_[i];
|
||||||
@ -527,11 +579,18 @@ void LruSessionCache::InsertEntry(std::shared_ptr<CompletionSession> session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClangCompleteManager::ParseRequest::ParseRequest(const std::string& path)
|
ClangCompleteManager::ParseRequest::ParseRequest(const std::string& path)
|
||||||
: request_time(std::chrono::high_resolution_clock::now()), path(path) {}
|
: request_time(std::chrono::high_resolution_clock::now()), path(path) {}
|
||||||
|
|
||||||
ClangCompleteManager::ClangCompleteManager(Config* config, Project* project, WorkingFiles* working_files, OnDiagnostic on_diagnostic)
|
ClangCompleteManager::ClangCompleteManager(Config* config,
|
||||||
: config_(config), project_(project), working_files_(working_files), on_diagnostic_(on_diagnostic),
|
Project* project,
|
||||||
view_sessions_(kMaxViewSessions), edit_sessions_(kMaxEditSessions) {
|
WorkingFiles* working_files,
|
||||||
|
OnDiagnostic on_diagnostic)
|
||||||
|
: config_(config),
|
||||||
|
project_(project),
|
||||||
|
working_files_(working_files),
|
||||||
|
on_diagnostic_(on_diagnostic),
|
||||||
|
view_sessions_(kMaxViewSessions),
|
||||||
|
edit_sessions_(kMaxEditSessions) {
|
||||||
new std::thread([&]() {
|
new std::thread([&]() {
|
||||||
SetCurrentThreadName("completequery");
|
SetCurrentThreadName("completequery");
|
||||||
CompletionQueryMain(this);
|
CompletionQueryMain(this);
|
||||||
@ -550,7 +609,9 @@ ClangCompleteManager::ClangCompleteManager(Config* config, Project* project, Wor
|
|||||||
|
|
||||||
ClangCompleteManager::~ClangCompleteManager() {}
|
ClangCompleteManager::~ClangCompleteManager() {}
|
||||||
|
|
||||||
void ClangCompleteManager::CodeComplete(const lsTextDocumentPositionParams& completion_location, const OnComplete& on_complete) {
|
void ClangCompleteManager::CodeComplete(
|
||||||
|
const lsTextDocumentPositionParams& completion_location,
|
||||||
|
const OnComplete& on_complete) {
|
||||||
// completion thread will create the CompletionSession if needed.
|
// completion thread will create the CompletionSession if needed.
|
||||||
|
|
||||||
auto request = MakeUnique<CompletionRequest>();
|
auto request = MakeUnique<CompletionRequest>();
|
||||||
@ -572,9 +633,10 @@ void ClangCompleteManager::NotifyView(const std::string& filename) {
|
|||||||
if (view_sessions_.TryGetEntry(filename))
|
if (view_sessions_.TryGetEntry(filename))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::cerr << "[complete] Creating new edit code completion session for " << filename << std::endl;
|
std::cerr << "[complete] Creating new edit code completion session for "
|
||||||
|
<< filename << std::endl;
|
||||||
view_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
view_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
||||||
project_->FindCompilationEntryForFile(filename), working_files_));
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
parse_requests_.Enqueue(ParseRequest(filename));
|
parse_requests_.Enqueue(ParseRequest(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,14 +652,15 @@ void ClangCompleteManager::NotifyEdit(const std::string& filename) {
|
|||||||
if (edit_sessions_.TryGetEntry(filename))
|
if (edit_sessions_.TryGetEntry(filename))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> session = view_sessions_.TryTakeEntry(filename);
|
std::shared_ptr<CompletionSession> session =
|
||||||
|
view_sessions_.TryTakeEntry(filename);
|
||||||
if (session) {
|
if (session) {
|
||||||
edit_sessions_.InsertEntry(session);
|
edit_sessions_.InsertEntry(session);
|
||||||
}
|
} else {
|
||||||
else {
|
std::cerr << "[complete] Creating new edit code completion session for "
|
||||||
std::cerr << "[complete] Creating new edit code completion session for " << filename << std::endl;
|
<< filename << std::endl;
|
||||||
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
||||||
project_->FindCompilationEntryForFile(filename), working_files_));
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
parse_requests_.PriorityEnqueue(ParseRequest(filename));
|
parse_requests_.PriorityEnqueue(ParseRequest(filename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -610,18 +673,22 @@ void ClangCompleteManager::NotifySave(const std::string& filename) {
|
|||||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
|
|
||||||
if (!edit_sessions_.TryGetEntry(filename)) {
|
if (!edit_sessions_.TryGetEntry(filename)) {
|
||||||
std::cerr << "[complete] Creating new edit code completion session for " << filename << std::endl;
|
std::cerr << "[complete] Creating new edit code completion session for "
|
||||||
|
<< filename << std::endl;
|
||||||
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
||||||
project_->FindCompilationEntryForFile(filename), working_files_));
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_requests_.PriorityEnqueue(ParseRequest(filename));
|
parse_requests_.PriorityEnqueue(ParseRequest(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(const std::string& filename, bool create_if_needed) {
|
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
|
||||||
|
const std::string& filename,
|
||||||
|
bool create_if_needed) {
|
||||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> session = edit_sessions_.TryGetEntry(filename);
|
std::shared_ptr<CompletionSession> session =
|
||||||
|
edit_sessions_.TryGetEntry(filename);
|
||||||
|
|
||||||
if (!session)
|
if (!session)
|
||||||
session = view_sessions_.TryGetEntry(filename);
|
session = view_sessions_.TryGetEntry(filename);
|
||||||
@ -630,7 +697,7 @@ std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(const std
|
|||||||
// Create new session. Default to edited_sessions_ since invoking code
|
// Create new session. Default to edited_sessions_ since invoking code
|
||||||
// completion almost certainly implies an edit.
|
// completion almost certainly implies an edit.
|
||||||
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
|
||||||
project_->FindCompilationEntryForFile(filename), working_files_));
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
session = edit_sessions_.TryGetEntry(filename);
|
session = edit_sessions_.TryGetEntry(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +13,15 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct CompletionSession : public std::enable_shared_from_this<CompletionSession> {
|
struct CompletionSession
|
||||||
|
: public std::enable_shared_from_this<CompletionSession> {
|
||||||
Project::Entry file;
|
Project::Entry file;
|
||||||
WorkingFiles* working_files;
|
WorkingFiles* working_files;
|
||||||
clang::Index index;
|
clang::Index index;
|
||||||
|
|
||||||
// When |tu| was last parsed.
|
// When |tu| was last parsed.
|
||||||
optional<std::chrono::time_point<std::chrono::high_resolution_clock>> tu_last_parsed_at;
|
optional<std::chrono::time_point<std::chrono::high_resolution_clock>>
|
||||||
|
tu_last_parsed_at;
|
||||||
|
|
||||||
// Acquired when |tu| is being used.
|
// Acquired when |tu| is being used.
|
||||||
std::mutex tu_lock;
|
std::mutex tu_lock;
|
||||||
@ -47,8 +49,12 @@ struct LruSessionCache {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ClangCompleteManager {
|
struct ClangCompleteManager {
|
||||||
using OnDiagnostic = std::function<void(std::string path, NonElidedVector<lsDiagnostic> diagnostics)>;
|
using OnDiagnostic =
|
||||||
using OnComplete = std::function<void(const NonElidedVector<lsCompletionItem>& results, bool is_cached_result)>;
|
std::function<void(std::string path,
|
||||||
|
NonElidedVector<lsDiagnostic> diagnostics)>;
|
||||||
|
using OnComplete =
|
||||||
|
std::function<void(const NonElidedVector<lsCompletionItem>& results,
|
||||||
|
bool is_cached_result)>;
|
||||||
|
|
||||||
struct ParseRequest {
|
struct ParseRequest {
|
||||||
ParseRequest(const std::string& path);
|
ParseRequest(const std::string& path);
|
||||||
@ -62,7 +68,10 @@ struct ClangCompleteManager {
|
|||||||
bool is_user_completion = false;
|
bool is_user_completion = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClangCompleteManager(Config* config, Project* project, WorkingFiles* working_files, OnDiagnostic on_diagnostic);
|
ClangCompleteManager(Config* config,
|
||||||
|
Project* project,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
OnDiagnostic on_diagnostic);
|
||||||
~ClangCompleteManager();
|
~ClangCompleteManager();
|
||||||
|
|
||||||
// Start a code completion at the given location. |on_complete| will run when
|
// Start a code completion at the given location. |on_complete| will run when
|
||||||
@ -79,7 +88,8 @@ struct ClangCompleteManager {
|
|||||||
// triggers a reparse.
|
// triggers a reparse.
|
||||||
void NotifySave(const std::string& filename);
|
void NotifySave(const std::string& filename);
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> TryGetSession(const std::string& filename, bool create_if_needed);
|
std::shared_ptr<CompletionSession> TryGetSession(const std::string& filename,
|
||||||
|
bool create_if_needed);
|
||||||
|
|
||||||
// TODO: make these configurable.
|
// TODO: make these configurable.
|
||||||
const int kMaxViewSessions = 1;
|
const int kMaxViewSessions = 1;
|
||||||
@ -108,5 +118,6 @@ struct ClangCompleteManager {
|
|||||||
std::mutex delayed_diagnostic_wakeup_mtx_;
|
std::mutex delayed_diagnostic_wakeup_mtx_;
|
||||||
std::condition_variable delayed_diagnostic_wakeup_cv_;
|
std::condition_variable delayed_diagnostic_wakeup_cv_;
|
||||||
// Access under |delayed_diagnostic_wakeup_mtx_|.
|
// Access under |delayed_diagnostic_wakeup_mtx_|.
|
||||||
optional<lsTextDocumentPositionParams> delayed_diagnostic_last_completion_position_;
|
optional<lsTextDocumentPositionParams>
|
||||||
|
delayed_diagnostic_last_completion_position_;
|
||||||
};
|
};
|
||||||
|
@ -10,24 +10,24 @@ lsRange GetLsRangeForFixIt(const CXSourceRange& range) {
|
|||||||
CXSourceLocation end = clang_getRangeEnd(range);
|
CXSourceLocation end = clang_getRangeEnd(range);
|
||||||
|
|
||||||
unsigned int start_line, start_column;
|
unsigned int start_line, start_column;
|
||||||
clang_getSpellingLocation(start, nullptr, &start_line, &start_column, nullptr);
|
clang_getSpellingLocation(start, nullptr, &start_line, &start_column,
|
||||||
|
nullptr);
|
||||||
unsigned int end_line, end_column;
|
unsigned int end_line, end_column;
|
||||||
clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr);
|
clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr);
|
||||||
|
|
||||||
return lsRange(
|
return lsRange(lsPosition(start_line - 1, start_column - 1) /*start*/,
|
||||||
lsPosition(start_line - 1, start_column - 1) /*start*/,
|
lsPosition(end_line - 1, end_column) /*end*/);
|
||||||
lsPosition(end_line - 1, end_column) /*end*/);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
optional<lsDiagnostic> BuildAndDisposeDiagnostic(
|
optional<lsDiagnostic> BuildAndDisposeDiagnostic(CXDiagnostic diagnostic,
|
||||||
CXDiagnostic diagnostic, const std::string& path) {
|
const std::string& path) {
|
||||||
// Get diagnostic location.
|
// Get diagnostic location.
|
||||||
CXFile file;
|
CXFile file;
|
||||||
unsigned int line, column;
|
unsigned int line, column;
|
||||||
clang_getSpellingLocation(
|
clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file,
|
||||||
clang_getDiagnosticLocation(diagnostic), &file, &line, &column, nullptr);
|
&line, &column, nullptr);
|
||||||
|
|
||||||
// Only report diagnostics in the same file. Using
|
// Only report diagnostics in the same file. Using
|
||||||
// clang_Location_isInSystemHeader causes crashes for some reason.
|
// clang_Location_isInSystemHeader causes crashes for some reason.
|
||||||
@ -43,12 +43,15 @@ optional<lsDiagnostic> BuildAndDisposeDiagnostic(
|
|||||||
// TODO: ls_diagnostic.range is lsRange, we have Range. We should only be
|
// TODO: ls_diagnostic.range is lsRange, we have Range. We should only be
|
||||||
// storing Range types when inside the indexer so that index <-> buffer
|
// storing Range types when inside the indexer so that index <-> buffer
|
||||||
// remapping logic is applied.
|
// remapping logic is applied.
|
||||||
ls_diagnostic.range = lsRange(lsPosition(line - 1, column), lsPosition(line - 1, column));
|
ls_diagnostic.range =
|
||||||
|
lsRange(lsPosition(line - 1, column), lsPosition(line - 1, column));
|
||||||
|
|
||||||
ls_diagnostic.message = clang::ToString(clang_getDiagnosticSpelling(diagnostic));
|
ls_diagnostic.message =
|
||||||
|
clang::ToString(clang_getDiagnosticSpelling(diagnostic));
|
||||||
|
|
||||||
// Append the flag that enables this diagnostic, ie, [-Wswitch]
|
// Append the flag that enables this diagnostic, ie, [-Wswitch]
|
||||||
std::string enabling_flag = clang::ToString(clang_getDiagnosticOption(diagnostic, nullptr));
|
std::string enabling_flag =
|
||||||
|
clang::ToString(clang_getDiagnosticOption(diagnostic, nullptr));
|
||||||
if (!enabling_flag.empty())
|
if (!enabling_flag.empty())
|
||||||
ls_diagnostic.message += " [" + enabling_flag + "]";
|
ls_diagnostic.message += " [" + enabling_flag + "]";
|
||||||
|
|
||||||
|
@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
#include <clang-c/Index.h>
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
using namespace std::experimental;
|
using namespace std::experimental;
|
||||||
|
|
||||||
optional<lsDiagnostic> BuildAndDisposeDiagnostic(
|
optional<lsDiagnostic> BuildAndDisposeDiagnostic(CXDiagnostic diagnostic,
|
||||||
CXDiagnostic diagnostic, const std::string& path);
|
const std::string& path);
|
||||||
|
|
||||||
// Returns the absolute path to |file|.
|
// Returns the absolute path to |file|.
|
||||||
std::string FileName(CXFile file);
|
std::string FileName(CXFile file);
|
||||||
|
1696
src/command_line.cc
1696
src/command_line.cc
File diff suppressed because it is too large
Load Diff
36
src/config.h
36
src/config.h
@ -17,7 +17,7 @@ struct Config {
|
|||||||
// If true, project paths that were skipped by the whitelist/blacklist will
|
// If true, project paths that were skipped by the whitelist/blacklist will
|
||||||
// be logged.
|
// be logged.
|
||||||
bool logSkippedPathsForIndex = false;
|
bool logSkippedPathsForIndex = false;
|
||||||
|
|
||||||
// Maximum workspace search results.
|
// Maximum workspace search results.
|
||||||
int maxWorkspaceSearchResults = 1000;
|
int maxWorkspaceSearchResults = 1000;
|
||||||
|
|
||||||
@ -63,26 +63,30 @@ struct Config {
|
|||||||
int clientVersion = 0;
|
int clientVersion = 0;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Config,
|
MAKE_REFLECT_STRUCT(Config,
|
||||||
cacheDirectory,
|
cacheDirectory,
|
||||||
|
|
||||||
extraClangArguments,
|
extraClangArguments,
|
||||||
|
|
||||||
indexWhitelist, indexBlacklist,
|
indexWhitelist,
|
||||||
logSkippedPathsForIndex,
|
indexBlacklist,
|
||||||
|
logSkippedPathsForIndex,
|
||||||
|
|
||||||
maxWorkspaceSearchResults,
|
maxWorkspaceSearchResults,
|
||||||
indexerCount,
|
indexerCount,
|
||||||
enableIndexing, enableCacheWrite, enableCacheRead,
|
enableIndexing,
|
||||||
|
enableCacheWrite,
|
||||||
|
enableCacheRead,
|
||||||
|
|
||||||
includeCompletionMaximumPathLength,
|
includeCompletionMaximumPathLength,
|
||||||
includeCompletionWhitelistLiteralEnding,
|
includeCompletionWhitelistLiteralEnding,
|
||||||
includeCompletionWhitelist, includeCompletionBlacklist,
|
includeCompletionWhitelist,
|
||||||
|
includeCompletionBlacklist,
|
||||||
|
|
||||||
showDocumentLinksOnIncludes,
|
showDocumentLinksOnIncludes,
|
||||||
|
|
||||||
diagnosticsOnParse,
|
diagnosticsOnParse,
|
||||||
diagnosticsOnCodeCompletion,
|
diagnosticsOnCodeCompletion,
|
||||||
|
|
||||||
codeLensOnLocalVariables,
|
codeLensOnLocalVariables,
|
||||||
|
|
||||||
clientVersion);
|
clientVersion);
|
@ -6,7 +6,8 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
|
bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) {
|
||||||
return a.data[0] == b.data[0] && a.data[1] == b.data[1] && a.data[2] == b.data[2];
|
return a.data[0] == b.data[0] && a.data[1] == b.data[1] &&
|
||||||
|
a.data[2] == b.data[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileConsumer::SharedState::Mark(const std::string& file) {
|
bool FileConsumer::SharedState::Mark(const std::string& file) {
|
||||||
@ -21,7 +22,8 @@ void FileConsumer::SharedState::Reset(const std::string& file) {
|
|||||||
files.erase(it);
|
files.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileConsumer::FileConsumer(SharedState* shared_state, const std::string& parse_file)
|
FileConsumer::FileConsumer(SharedState* shared_state,
|
||||||
|
const std::string& parse_file)
|
||||||
: shared_(shared_state), parse_file_(parse_file) {}
|
: shared_(shared_state), parse_file_(parse_file) {}
|
||||||
|
|
||||||
IndexFile* FileConsumer::TryConsumeFile(CXFile file, bool* is_first_ownership) {
|
IndexFile* FileConsumer::TryConsumeFile(CXFile file, bool* is_first_ownership) {
|
||||||
@ -86,7 +88,8 @@ void FileConsumer::EmitError(CXFile file) const {
|
|||||||
std::string file_name = clang::ToString(clang_getFileName(file));
|
std::string file_name = clang::ToString(clang_getFileName(file));
|
||||||
// TODO: Investigate this more, why can we get an empty file name?
|
// TODO: Investigate this more, why can we get an empty file name?
|
||||||
if (!file_name.empty()) {
|
if (!file_name.empty()) {
|
||||||
std::string error_message = "Could not get unique file id for " + file_name + " when parsing " + parse_file_;
|
std::string error_message = "Could not get unique file id for " +
|
||||||
|
file_name + " when parsing " + parse_file_;
|
||||||
std::cerr << error_message << std::endl;
|
std::cerr << error_message << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_set>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
||||||
struct IndexFile;
|
struct IndexFile;
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@ std::string ElideLongPath(Config* config, const std::string& path) {
|
|||||||
return ".." + path.substr(start + 2);
|
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) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < result.size() && i < trimmer.size()) {
|
while (i < result.size() && i < trimmer.size()) {
|
||||||
char a = result[i];
|
char a = result[i];
|
||||||
@ -47,7 +48,9 @@ size_t TrimCommonPathPrefix(const std::string& result, const std::string& trimme
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true iff angle brackets should be used.
|
// 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 = 0;
|
size_t start = 0;
|
||||||
bool angle = false;
|
bool angle = false;
|
||||||
|
|
||||||
@ -73,7 +76,10 @@ bool TrimPath(Project* project, const std::string& project_root, std::string* in
|
|||||||
return angle;
|
return angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsCompletionItem BuildCompletionItem(Config* config, const std::string& path, bool use_angle_brackets, bool is_stl) {
|
lsCompletionItem BuildCompletionItem(Config* config,
|
||||||
|
const std::string& path,
|
||||||
|
bool use_angle_brackets,
|
||||||
|
bool is_stl) {
|
||||||
lsCompletionItem item;
|
lsCompletionItem item;
|
||||||
if (use_angle_brackets)
|
if (use_angle_brackets)
|
||||||
item.label = "#include <" + ElideLongPath(config, path) + ">";
|
item.label = "#include <" + ElideLongPath(config, path) + ">";
|
||||||
@ -111,15 +117,18 @@ void IncludeComplete::Rescan() {
|
|||||||
completion_items.clear();
|
completion_items.clear();
|
||||||
absolute_path_to_completion_item.clear();
|
absolute_path_to_completion_item.clear();
|
||||||
|
|
||||||
if (!match_ && (!config_->includeCompletionWhitelist.empty() || !config_->includeCompletionBlacklist.empty()))
|
if (!match_ && (!config_->includeCompletionWhitelist.empty() ||
|
||||||
match_ = MakeUnique<GroupMatch>(config_->includeCompletionWhitelist, config_->includeCompletionBlacklist);
|
!config_->includeCompletionBlacklist.empty()))
|
||||||
|
match_ = MakeUnique<GroupMatch>(config_->includeCompletionWhitelist,
|
||||||
|
config_->includeCompletionBlacklist);
|
||||||
|
|
||||||
is_scanning = true;
|
is_scanning = true;
|
||||||
WorkThread::StartThread("include_scanner", [this]() {
|
WorkThread::StartThread("include_scanner", [this]() {
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
InsertStlIncludes();
|
InsertStlIncludes();
|
||||||
InsertIncludesFromDirectory(config_->projectRoot, false /*use_angle_brackets*/);
|
InsertIncludesFromDirectory(config_->projectRoot,
|
||||||
|
false /*use_angle_brackets*/);
|
||||||
for (const std::string& dir : project_->quote_include_directories)
|
for (const std::string& dir : project_->quote_include_directories)
|
||||||
InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/);
|
InsertIncludesFromDirectory(dir, false /*use_angle_brackets*/);
|
||||||
for (const std::string& dir : project_->angle_include_directories)
|
for (const std::string& dir : project_->angle_include_directories)
|
||||||
@ -133,48 +142,60 @@ void IncludeComplete::Rescan() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IncludeComplete::AddFile(const std::string& absolute_path) {
|
void IncludeComplete::AddFile(const std::string& absolute_path) {
|
||||||
if (!EndsWithAny(absolute_path, config_->includeCompletionWhitelistLiteralEnding))
|
if (!EndsWithAny(absolute_path,
|
||||||
|
config_->includeCompletionWhitelistLiteralEnding))
|
||||||
return;
|
return;
|
||||||
if (match_ && !match_->IsMatch(absolute_path))
|
if (match_ && !match_->IsMatch(absolute_path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string trimmed_path = absolute_path;
|
std::string trimmed_path = absolute_path;
|
||||||
bool use_angle_brackets = TrimPath(project_, config_->projectRoot, &trimmed_path);
|
bool use_angle_brackets =
|
||||||
lsCompletionItem item = BuildCompletionItem(config_, trimmed_path, use_angle_brackets, false /*is_stl*/);
|
TrimPath(project_, config_->projectRoot, &trimmed_path);
|
||||||
|
lsCompletionItem item = BuildCompletionItem(
|
||||||
|
config_, trimmed_path, use_angle_brackets, false /*is_stl*/);
|
||||||
|
|
||||||
if (is_scanning) {
|
if (is_scanning) {
|
||||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||||
if (absolute_path_to_completion_item.insert(std::make_pair(absolute_path, completion_items.size())).second)
|
if (absolute_path_to_completion_item
|
||||||
|
.insert(std::make_pair(absolute_path, completion_items.size()))
|
||||||
|
.second)
|
||||||
completion_items.push_back(item);
|
completion_items.push_back(item);
|
||||||
}
|
} else {
|
||||||
else {
|
if (absolute_path_to_completion_item
|
||||||
if (absolute_path_to_completion_item.insert(std::make_pair(absolute_path, completion_items.size())).second)
|
.insert(std::make_pair(absolute_path, completion_items.size()))
|
||||||
|
.second)
|
||||||
completion_items.push_back(item);
|
completion_items.push_back(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IncludeComplete::InsertIncludesFromDirectory(
|
void IncludeComplete::InsertIncludesFromDirectory(std::string directory,
|
||||||
std::string directory,
|
bool use_angle_brackets) {
|
||||||
bool use_angle_brackets) {
|
|
||||||
directory = NormalizePath(directory);
|
directory = NormalizePath(directory);
|
||||||
EnsureEndsInSlash(directory);
|
EnsureEndsInSlash(directory);
|
||||||
|
|
||||||
std::vector<CompletionCandidate> results;
|
std::vector<CompletionCandidate> results;
|
||||||
GetFilesInFolder(directory, true /*recursive*/, false /*add_folder_to_path*/, [&](const std::string& path) {
|
GetFilesInFolder(
|
||||||
if (!EndsWithAny(path, config_->includeCompletionWhitelistLiteralEnding))
|
directory, true /*recursive*/, false /*add_folder_to_path*/,
|
||||||
return;
|
[&](const std::string& path) {
|
||||||
if (match_ && !match_->IsMatch(directory + path))
|
if (!EndsWithAny(path,
|
||||||
return;
|
config_->includeCompletionWhitelistLiteralEnding))
|
||||||
|
return;
|
||||||
|
if (match_ && !match_->IsMatch(directory + path))
|
||||||
|
return;
|
||||||
|
|
||||||
CompletionCandidate candidate;
|
CompletionCandidate candidate;
|
||||||
candidate.absolute_path = directory + path;
|
candidate.absolute_path = directory + path;
|
||||||
candidate.completion_item = BuildCompletionItem(config_, path, use_angle_brackets, false /*is_stl*/);
|
candidate.completion_item = BuildCompletionItem(
|
||||||
results.push_back(candidate);
|
config_, path, use_angle_brackets, false /*is_stl*/);
|
||||||
});
|
results.push_back(candidate);
|
||||||
|
});
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||||
for (const CompletionCandidate& result : results) {
|
for (const CompletionCandidate& result : results) {
|
||||||
if (absolute_path_to_completion_item.insert(std::make_pair(result.absolute_path, completion_items.size())).second)
|
if (absolute_path_to_completion_item
|
||||||
|
.insert(
|
||||||
|
std::make_pair(result.absolute_path, completion_items.size()))
|
||||||
|
.second)
|
||||||
completion_items.push_back(result.completion_item);
|
completion_items.push_back(result.completion_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,11 +203,13 @@ void IncludeComplete::InsertIncludesFromDirectory(
|
|||||||
void IncludeComplete::InsertStlIncludes() {
|
void IncludeComplete::InsertStlIncludes() {
|
||||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||||
for (const char* stl_header : kStandardLibraryIncludes) {
|
for (const char* stl_header : kStandardLibraryIncludes) {
|
||||||
completion_items.push_back(BuildCompletionItem(config_, stl_header, true /*use_angle_brackets*/, true /*is_stl*/));
|
completion_items.push_back(BuildCompletionItem(
|
||||||
|
config_, stl_header, true /*use_angle_brackets*/, true /*is_stl*/));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(const std::string& absolute_path) {
|
optional<lsCompletionItem> IncludeComplete::FindCompletionItemForAbsolutePath(
|
||||||
|
const std::string& absolute_path) {
|
||||||
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
std::lock_guard<std::mutex> lock(completion_items_mutex);
|
||||||
|
|
||||||
auto it = absolute_path_to_completion_item.find(absolute_path);
|
auto it = absolute_path_to_completion_item.find(absolute_path);
|
||||||
|
@ -18,18 +18,20 @@ struct IncludeComplete {
|
|||||||
// Ensures the one-off file is inside |completion_items|.
|
// Ensures the one-off file is inside |completion_items|.
|
||||||
void AddFile(const std::string& absolute_path);
|
void AddFile(const std::string& absolute_path);
|
||||||
|
|
||||||
// Scans the given directory and inserts all includes from this. This is a
|
// Scans the given directory and inserts all includes from this. This is a
|
||||||
// blocking function and should be run off the querydb thread.
|
// blocking function and should be run off the querydb thread.
|
||||||
void InsertIncludesFromDirectory(std::string directory, bool use_angle_brackets);
|
void InsertIncludesFromDirectory(std::string directory,
|
||||||
|
bool use_angle_brackets);
|
||||||
void InsertStlIncludes();
|
void InsertStlIncludes();
|
||||||
|
|
||||||
optional<lsCompletionItem> FindCompletionItemForAbsolutePath(const std::string& absolute_path);
|
optional<lsCompletionItem> FindCompletionItemForAbsolutePath(
|
||||||
|
const std::string& absolute_path);
|
||||||
|
|
||||||
// Guards |completion_items| when |is_scanning| is true.
|
// Guards |completion_items| when |is_scanning| is true.
|
||||||
std::mutex completion_items_mutex;
|
std::mutex completion_items_mutex;
|
||||||
std::atomic<bool> is_scanning;
|
std::atomic<bool> is_scanning;
|
||||||
std::vector<lsCompletionItem> completion_items;
|
std::vector<lsCompletionItem> completion_items;
|
||||||
|
|
||||||
// Absolute file path to the completion item in |completion_items|. Also
|
// Absolute file path to the completion item in |completion_items|. Also
|
||||||
// verifies that we only have one completion item per absolute path.
|
// verifies that we only have one completion item per absolute path.
|
||||||
// We cannot just scan |completion_items| for this information because the
|
// We cannot just scan |completion_items| for this information because the
|
||||||
@ -42,4 +44,3 @@ struct IncludeComplete {
|
|||||||
Project* project_;
|
Project* project_;
|
||||||
std::unique_ptr<GroupMatch> match_;
|
std::unique_ptr<GroupMatch> match_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
278
src/indexer.cc
278
src/indexer.cc
@ -14,7 +14,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on |Foobar| in DISALLOW_COPY(Foobar)
|
// TODO: See if we can use clang_indexLoc_getFileLocation to get a type ref on
|
||||||
|
// |Foobar| in DISALLOW_COPY(Foobar)
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -31,13 +32,13 @@ Range Resolve(const CXSourceRange& range, CXFile* cx_file = nullptr) {
|
|||||||
CXSourceLocation end = clang_getRangeEnd(range);
|
CXSourceLocation end = clang_getRangeEnd(range);
|
||||||
|
|
||||||
unsigned int start_line, start_column;
|
unsigned int start_line, start_column;
|
||||||
clang_getSpellingLocation(start, cx_file, &start_line, &start_column, nullptr);
|
clang_getSpellingLocation(start, cx_file, &start_line, &start_column,
|
||||||
|
nullptr);
|
||||||
unsigned int end_line, end_column;
|
unsigned int end_line, end_column;
|
||||||
clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr);
|
clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr);
|
||||||
|
|
||||||
return Range(
|
return Range(Position((int16_t)start_line, (int16_t)start_column) /*start*/,
|
||||||
Position((int16_t)start_line, (int16_t)start_column) /*start*/,
|
Position((int16_t)end_line, (int16_t)end_column) /*end*/);
|
||||||
Position((int16_t)end_line, (int16_t)end_column) /*end*/);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Range ResolveSpelling(const CXCursor& cx_cursor, CXFile* cx_file = nullptr) {
|
Range ResolveSpelling(const CXCursor& cx_cursor, CXFile* cx_file = nullptr) {
|
||||||
@ -50,19 +51,18 @@ Range ResolveExtent(const CXCursor& cx_cursor, CXFile* cx_file = nullptr) {
|
|||||||
return Resolve(cx_range, cx_file);
|
return Resolve(cx_range, cx_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct NamespaceHelper {
|
struct NamespaceHelper {
|
||||||
std::unordered_map<std::string, std::string> container_usr_to_qualified_name;
|
std::unordered_map<std::string, std::string> container_usr_to_qualified_name;
|
||||||
|
|
||||||
void RegisterQualifiedName(std::string usr,
|
void RegisterQualifiedName(std::string usr,
|
||||||
const CXIdxContainerInfo* container,
|
const CXIdxContainerInfo* container,
|
||||||
std::string qualified_name) {
|
std::string qualified_name) {
|
||||||
if (container) {
|
if (container) {
|
||||||
std::string container_usr = clang::Cursor(container->cursor).get_usr();
|
std::string container_usr = clang::Cursor(container->cursor).get_usr();
|
||||||
auto it = container_usr_to_qualified_name.find(container_usr);
|
auto it = container_usr_to_qualified_name.find(container_usr);
|
||||||
if (it != container_usr_to_qualified_name.end()) {
|
if (it != container_usr_to_qualified_name.end()) {
|
||||||
container_usr_to_qualified_name[usr] =
|
container_usr_to_qualified_name[usr] =
|
||||||
it->second + qualified_name + "::";
|
it->second + qualified_name + "::";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ struct NamespaceHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string QualifiedName(const CXIdxContainerInfo* container,
|
std::string QualifiedName(const CXIdxContainerInfo* container,
|
||||||
std::string unqualified_name) {
|
std::string unqualified_name) {
|
||||||
if (container) {
|
if (container) {
|
||||||
std::string container_usr = clang::Cursor(container->cursor).get_usr();
|
std::string container_usr = clang::Cursor(container->cursor).get_usr();
|
||||||
auto it = container_usr_to_qualified_name.find(container_usr);
|
auto it = container_usr_to_qualified_name.find(container_usr);
|
||||||
@ -109,12 +109,14 @@ struct IndexParam {
|
|||||||
FileConsumer* file_consumer = nullptr;
|
FileConsumer* file_consumer = nullptr;
|
||||||
NamespaceHelper ns;
|
NamespaceHelper ns;
|
||||||
|
|
||||||
IndexParam(clang::TranslationUnit* tu, FileConsumer* file_consumer) : tu(tu), file_consumer(file_consumer) {}
|
IndexParam(clang::TranslationUnit* tu, FileConsumer* file_consumer)
|
||||||
|
: tu(tu), file_consumer(file_consumer) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
|
IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
|
||||||
bool is_first_ownership = false;
|
bool is_first_ownership = false;
|
||||||
IndexFile* db = param->file_consumer->TryConsumeFile(file, &is_first_ownership);
|
IndexFile* db =
|
||||||
|
param->file_consumer->TryConsumeFile(file, &is_first_ownership);
|
||||||
|
|
||||||
// If this is the first time we have seen the file (ignoring if we are
|
// If this is the first time we have seen the file (ignoring if we are
|
||||||
// generating an index for it):
|
// generating an index for it):
|
||||||
@ -129,18 +131,21 @@ IndexFile* ConsumeFile(IndexParam* param, CXFile file) {
|
|||||||
|
|
||||||
// Set modification time.
|
// Set modification time.
|
||||||
optional<int64_t> modification_time = GetLastModificationTime(file_name);
|
optional<int64_t> modification_time = GetLastModificationTime(file_name);
|
||||||
LOG_IF_S(ERROR, !modification_time) << "Failed fetching modification time for " << file_name;
|
LOG_IF_S(ERROR, !modification_time)
|
||||||
|
<< "Failed fetching modification time for " << file_name;
|
||||||
if (modification_time)
|
if (modification_time)
|
||||||
param->file_modification_times[file_name] = *modification_time;
|
param->file_modification_times[file_name] = *modification_time;
|
||||||
|
|
||||||
// Capture file contents in |param->file_contents| if it was not specified
|
// Capture file contents in |param->file_contents| if it was not specified
|
||||||
// at the start of indexing.
|
// at the start of indexing.
|
||||||
if (db && param->file_contents.find(file_name) == param->file_contents.end()) {
|
if (db &&
|
||||||
|
param->file_contents.find(file_name) == param->file_contents.end()) {
|
||||||
optional<std::string> content = ReadContent(file_name);
|
optional<std::string> content = ReadContent(file_name);
|
||||||
if (content)
|
if (content)
|
||||||
param->file_contents[file_name] = *content;
|
param->file_contents[file_name] = *content;
|
||||||
else
|
else
|
||||||
LOG_S(ERROR) << "[indexer] Failed to read file content for " << file_name;
|
LOG_S(ERROR) << "[indexer] Failed to read file content for "
|
||||||
|
<< file_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,18 +184,20 @@ bool IsLocalSemanticContainer(CXCursorKind kind) {
|
|||||||
// actually being written in the source code.
|
// actually being written in the source code.
|
||||||
bool CanBeCalledImplicitly(CXIdxEntityKind kind) {
|
bool CanBeCalledImplicitly(CXIdxEntityKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case CXIdxEntity_CXXConstructor:
|
case CXIdxEntity_CXXConstructor:
|
||||||
case CXIdxEntity_CXXConversionFunction:
|
case CXIdxEntity_CXXConversionFunction:
|
||||||
case CXIdxEntity_CXXDestructor:
|
case CXIdxEntity_CXXDestructor:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the cursor spelling contains the given string. This is
|
// Returns true if the cursor spelling contains the given string. This is
|
||||||
// useful to check for implicit function calls.
|
// useful to check for implicit function calls.
|
||||||
bool CursorSpellingContainsString(CXCursor cursor, CXTranslationUnit cx_tu, std::string scanning_for) {
|
bool CursorSpellingContainsString(CXCursor cursor,
|
||||||
|
CXTranslationUnit cx_tu,
|
||||||
|
std::string scanning_for) {
|
||||||
CXSourceRange range = clang_Cursor_getSpellingNameRange(cursor, 0, 0);
|
CXSourceRange range = clang_Cursor_getSpellingNameRange(cursor, 0, 0);
|
||||||
CXToken* tokens;
|
CXToken* tokens;
|
||||||
unsigned num_tokens;
|
unsigned num_tokens;
|
||||||
@ -213,7 +220,8 @@ bool CursorSpellingContainsString(CXCursor cursor, CXTranslationUnit cx_tu, std:
|
|||||||
|
|
||||||
// Returns the document content for the given range. May not work perfectly
|
// Returns the document content for the given range. May not work perfectly
|
||||||
// when there are tabs instead of spaces.
|
// when there are tabs instead of spaces.
|
||||||
std::string GetDocumentContentInRange(CXTranslationUnit cx_tu, CXSourceRange range) {
|
std::string GetDocumentContentInRange(CXTranslationUnit cx_tu,
|
||||||
|
CXSourceRange range) {
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
CXToken* tokens;
|
CXToken* tokens;
|
||||||
@ -227,7 +235,8 @@ std::string GetDocumentContentInRange(CXTranslationUnit cx_tu, CXSourceRange ran
|
|||||||
Range token_range = Resolve(clang_getTokenExtent(cx_tu, tokens[i]));
|
Range token_range = Resolve(clang_getTokenExtent(cx_tu, tokens[i]));
|
||||||
if (previous_token_range) {
|
if (previous_token_range) {
|
||||||
// Insert newlines.
|
// Insert newlines.
|
||||||
int16_t line_delta = token_range.start.line - previous_token_range->end.line;
|
int16_t line_delta =
|
||||||
|
token_range.start.line - previous_token_range->end.line;
|
||||||
assert(line_delta >= 0);
|
assert(line_delta >= 0);
|
||||||
if (line_delta > 0) {
|
if (line_delta > 0) {
|
||||||
result.append((size_t)line_delta, '\n');
|
result.append((size_t)line_delta, '\n');
|
||||||
@ -235,7 +244,8 @@ std::string GetDocumentContentInRange(CXTranslationUnit cx_tu, CXSourceRange ran
|
|||||||
previous_token_range->end.column = 0;
|
previous_token_range->end.column = 0;
|
||||||
}
|
}
|
||||||
// Insert spaces.
|
// Insert spaces.
|
||||||
int16_t column_delta = token_range.start.column - previous_token_range->end.column;
|
int16_t column_delta =
|
||||||
|
token_range.start.column - previous_token_range->end.column;
|
||||||
assert(column_delta >= 0);
|
assert(column_delta >= 0);
|
||||||
result.append((size_t)column_delta, ' ');
|
result.append((size_t)column_delta, ' ');
|
||||||
}
|
}
|
||||||
@ -381,7 +391,7 @@ void UniqueAdd(std::vector<T>& values, T value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdCache::IdCache(const std::string& primary_file)
|
IdCache::IdCache(const std::string& primary_file)
|
||||||
: primary_file(primary_file) {}
|
: primary_file(primary_file) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool Contains(const std::vector<T>& vec, const T& element) {
|
bool Contains(const std::vector<T>& vec, const T& element) {
|
||||||
@ -640,7 +650,6 @@ optional<IndexTypeId> AddDeclTypeUsages(
|
|||||||
clang::Cursor decl_cursor,
|
clang::Cursor decl_cursor,
|
||||||
const CXIdxContainerInfo* semantic_container,
|
const CXIdxContainerInfo* semantic_container,
|
||||||
const CXIdxContainerInfo* lexical_container) {
|
const CXIdxContainerInfo* lexical_container) {
|
||||||
|
|
||||||
// std::cerr << std::endl << "AddDeclUsages " << decl_cursor.get_spelling() <<
|
// std::cerr << std::endl << "AddDeclUsages " << decl_cursor.get_spelling() <<
|
||||||
// std::endl;
|
// std::endl;
|
||||||
// Dump(decl_cursor);
|
// Dump(decl_cursor);
|
||||||
@ -838,20 +847,20 @@ bool AreEqualLocations(CXIdxLoc loc, CXCursor cursor) {
|
|||||||
// clang_Cursor_getSpellingNameRange
|
// clang_Cursor_getSpellingNameRange
|
||||||
|
|
||||||
return clang_equalLocations(
|
return clang_equalLocations(
|
||||||
clang_indexLoc_getCXSourceLocation(loc),
|
clang_indexLoc_getCXSourceLocation(loc),
|
||||||
//clang_getRangeStart(clang_getCursorExtent(cursor)));
|
// clang_getRangeStart(clang_getCursorExtent(cursor)));
|
||||||
clang_getRangeStart(clang_Cursor_getSpellingNameRange(cursor, 0, 0)));
|
clang_getRangeStart(clang_Cursor_getSpellingNameRange(cursor, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clang::VisiterResult VisitMacroDefinitionAndExpansions(clang::Cursor cursor,
|
||||||
|
clang::Cursor parent,
|
||||||
|
IndexParam* param) {
|
||||||
clang::VisiterResult VisitMacroDefinitionAndExpansions(clang::Cursor cursor, clang::Cursor parent, IndexParam* param) {
|
|
||||||
switch (cursor.get_kind()) {
|
switch (cursor.get_kind()) {
|
||||||
case CXCursor_MacroDefinition:
|
case CXCursor_MacroDefinition:
|
||||||
case CXCursor_MacroExpansion: {
|
case CXCursor_MacroExpansion: {
|
||||||
// Resolve location, find IndexFile instance.
|
// Resolve location, find IndexFile instance.
|
||||||
CXSourceRange cx_source_range = clang_Cursor_getSpellingNameRange(cursor.cx_cursor, 0, 0);
|
CXSourceRange cx_source_range =
|
||||||
|
clang_Cursor_getSpellingNameRange(cursor.cx_cursor, 0, 0);
|
||||||
CXSourceLocation start = clang_getRangeStart(cx_source_range);
|
CXSourceLocation start = clang_getRangeStart(cx_source_range);
|
||||||
if (clang_Location_isInSystemHeader(start))
|
if (clang_Location_isInSystemHeader(start))
|
||||||
break;
|
break;
|
||||||
@ -881,7 +890,8 @@ clang::VisiterResult VisitMacroDefinitionAndExpansions(clang::Cursor cursor, cla
|
|||||||
var_def->def.is_local = false;
|
var_def->def.is_local = false;
|
||||||
var_def->def.is_macro = true;
|
var_def->def.is_macro = true;
|
||||||
var_def->def.definition_spelling = decl_loc_spelling;
|
var_def->def.definition_spelling = decl_loc_spelling;
|
||||||
var_def->def.definition_extent = ResolveExtent(cursor.cx_cursor);;
|
var_def->def.definition_extent = ResolveExtent(cursor.cx_cursor);
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -945,13 +955,16 @@ clang::VisiterResult VisitMacroDefinitionAndExpansions(clang::Cursor cursor, cla
|
|||||||
|
|
||||||
|
|
||||||
void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||||
if (!kIndexStdDeclarations && clang_Location_isInSystemHeader(clang_indexLoc_getCXSourceLocation(decl->loc)))
|
if (!kIndexStdDeclarations &&
|
||||||
|
clang_Location_isInSystemHeader(
|
||||||
|
clang_indexLoc_getCXSourceLocation(decl->loc)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert(AreEqualLocations(decl->loc, decl->cursor));
|
assert(AreEqualLocations(decl->loc, decl->cursor));
|
||||||
|
|
||||||
CXFile file;
|
CXFile file;
|
||||||
clang_getSpellingLocation(clang_indexLoc_getCXSourceLocation(decl->loc), &file, nullptr, nullptr, nullptr);
|
clang_getSpellingLocation(clang_indexLoc_getCXSourceLocation(decl->loc),
|
||||||
|
&file, nullptr, nullptr, nullptr);
|
||||||
IndexParam* param = static_cast<IndexParam*>(client_data);
|
IndexParam* param = static_cast<IndexParam*>(client_data);
|
||||||
IndexFile* db = ConsumeFile(param, file);
|
IndexFile* db = ConsumeFile(param, file);
|
||||||
if (!db)
|
if (!db)
|
||||||
@ -959,8 +972,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
|
|
||||||
NamespaceHelper* ns = ¶m->ns;
|
NamespaceHelper* ns = ¶m->ns;
|
||||||
|
|
||||||
|
// std::cerr << "DECL kind=" << decl->entityInfo->kind << " at " <<
|
||||||
//std::cerr << "DECL kind=" << decl->entityInfo->kind << " at " << db->id_cache.Resolve(decl->cursor, false).ToPrettyString(&db->id_cache) << std::endl;
|
// db->id_cache.Resolve(decl->cursor, false).ToPrettyString(&db->id_cache) <<
|
||||||
|
// std::endl;
|
||||||
|
|
||||||
switch (decl->entityInfo->kind) {
|
switch (decl->entityInfo->kind) {
|
||||||
case CXIdxEntity_CXXNamespace: {
|
case CXIdxEntity_CXXNamespace: {
|
||||||
@ -993,18 +1007,23 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// if (!decl->isRedeclaration) {
|
// if (!decl->isRedeclaration) {
|
||||||
var->def.short_name = decl->entityInfo->name;
|
var->def.short_name = decl->entityInfo->name;
|
||||||
|
|
||||||
std::string type_name = clang::ToString(clang_getTypeSpelling(clang_getCursorType(decl->cursor)));
|
std::string type_name = clang::ToString(
|
||||||
var->def.detailed_name = type_name + " " + ns->QualifiedName(decl->semanticContainer, var->def.short_name);
|
clang_getTypeSpelling(clang_getCursorType(decl->cursor)));
|
||||||
|
var->def.detailed_name =
|
||||||
|
type_name + " " +
|
||||||
|
ns->QualifiedName(decl->semanticContainer, var->def.short_name);
|
||||||
|
|
||||||
var->def.is_local = !decl->semanticContainer || IsLocalSemanticContainer(decl->semanticContainer->cursor.kind);
|
var->def.is_local =
|
||||||
|
!decl->semanticContainer ||
|
||||||
|
IsLocalSemanticContainer(decl->semanticContainer->cursor.kind);
|
||||||
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (decl->isDefinition) {
|
if (decl->isDefinition) {
|
||||||
var->def.definition_spelling = ResolveSpelling(decl->cursor);
|
var->def.definition_spelling = ResolveSpelling(decl->cursor);
|
||||||
var->def.definition_extent = ResolveExtent(decl->cursor);;
|
var->def.definition_extent = ResolveExtent(decl->cursor);
|
||||||
}
|
;
|
||||||
else {
|
} else {
|
||||||
var->def.declaration = ResolveSpelling(decl->cursor);
|
var->def.declaration = ResolveSpelling(decl->cursor);
|
||||||
}
|
}
|
||||||
UniqueAdd(var->uses, decl_loc_spelling);
|
UniqueAdd(var->uses, decl_loc_spelling);
|
||||||
@ -1020,17 +1039,19 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// the function declaration is encountered since we won't receive ParmDecl
|
// the function declaration is encountered since we won't receive ParmDecl
|
||||||
// declarations for unnamed parameters.
|
// declarations for unnamed parameters.
|
||||||
// TODO: See if we can remove this function call.
|
// TODO: See if we can remove this function call.
|
||||||
AddDeclTypeUsages(
|
AddDeclTypeUsages(db, decl_cursor, decl->semanticContainer,
|
||||||
db, decl_cursor,
|
decl->lexicalContainer);
|
||||||
decl->semanticContainer, decl->lexicalContainer);
|
|
||||||
|
|
||||||
// We don't need to assign declaring type multiple times if this variable
|
// We don't need to assign declaring type multiple times if this variable
|
||||||
// has already been seen.
|
// has already been seen.
|
||||||
if (!decl->isRedeclaration) {
|
if (!decl->isRedeclaration) {
|
||||||
optional<IndexTypeId> var_type = ResolveToDeclarationType(db, decl_cursor);
|
optional<IndexTypeId> var_type =
|
||||||
|
ResolveToDeclarationType(db, decl_cursor);
|
||||||
if (var_type.has_value()) {
|
if (var_type.has_value()) {
|
||||||
// Don't treat enum definition variables as instantiations.
|
// Don't treat enum definition variables as instantiations.
|
||||||
bool is_enum_member = decl->semanticContainer && decl->semanticContainer->cursor.kind == CXCursor_EnumDecl;
|
bool is_enum_member =
|
||||||
|
decl->semanticContainer &&
|
||||||
|
decl->semanticContainer->cursor.kind == CXCursor_EnumDecl;
|
||||||
if (!is_enum_member)
|
if (!is_enum_member)
|
||||||
db->Resolve(var_type.value())->instances.push_back(var_id);
|
db->Resolve(var_type.value())->instances.push_back(var_id);
|
||||||
|
|
||||||
@ -1038,10 +1059,11 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor handlers so more things are under 'if (!decl->isRedeclaration)'
|
// TODO: Refactor handlers so more things are under 'if
|
||||||
|
// (!decl->isRedeclaration)'
|
||||||
if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) {
|
if (decl->isDefinition && IsTypeDefinition(decl->semanticContainer)) {
|
||||||
IndexTypeId declaring_type_id =
|
IndexTypeId declaring_type_id =
|
||||||
db->ToTypeId(decl->semanticContainer->cursor);
|
db->ToTypeId(decl->semanticContainer->cursor);
|
||||||
IndexType* declaring_type_def = db->Resolve(declaring_type_id);
|
IndexType* declaring_type_def = db->Resolve(declaring_type_id);
|
||||||
var->def.declaring_type = declaring_type_id;
|
var->def.declaring_type = declaring_type_id;
|
||||||
declaring_type_def->def.vars.push_back(var_id);
|
declaring_type_def->def.vars.push_back(var_id);
|
||||||
@ -1060,7 +1082,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
Range decl_extent = ResolveExtent(decl->cursor);
|
Range decl_extent = ResolveExtent(decl->cursor);
|
||||||
|
|
||||||
clang::Cursor decl_cursor = decl->cursor;
|
clang::Cursor decl_cursor = decl->cursor;
|
||||||
clang::Cursor decl_cursor_resolved = decl_cursor.template_specialization_to_template_definition();
|
clang::Cursor decl_cursor_resolved =
|
||||||
|
decl_cursor.template_specialization_to_template_definition();
|
||||||
bool is_template_specialization = decl_cursor != decl_cursor_resolved;
|
bool is_template_specialization = decl_cursor != decl_cursor_resolved;
|
||||||
|
|
||||||
IndexFuncId func_id = db->ToFuncId(decl_cursor_resolved.cx_cursor);
|
IndexFuncId func_id = db->ToFuncId(decl_cursor_resolved.cx_cursor);
|
||||||
@ -1068,8 +1091,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
|
|
||||||
// We don't actually need to know the return type, but we need to mark it
|
// We don't actually need to know the return type, but we need to mark it
|
||||||
// as an interesting usage.
|
// as an interesting usage.
|
||||||
AddDeclTypeUsages(db, decl_cursor,
|
AddDeclTypeUsages(db, decl_cursor, decl->semanticContainer,
|
||||||
decl->semanticContainer, decl->lexicalContainer);
|
decl->lexicalContainer);
|
||||||
|
|
||||||
// Add definition or declaration. This is a bit tricky because we treat
|
// Add definition or declaration. This is a bit tricky because we treat
|
||||||
// template specializations as declarations, even though they are
|
// template specializations as declarations, even though they are
|
||||||
@ -1077,16 +1100,16 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// TODO: Support multiple function definitions, which is common for
|
// TODO: Support multiple function definitions, which is common for
|
||||||
// template specializations.
|
// template specializations.
|
||||||
if (decl->isDefinition && !is_template_specialization) {
|
if (decl->isDefinition && !is_template_specialization) {
|
||||||
//assert(!func->def.definition_spelling);
|
// assert(!func->def.definition_spelling);
|
||||||
//assert(!func->def.definition_extent);
|
// assert(!func->def.definition_extent);
|
||||||
func->def.definition_spelling = decl_spelling;
|
func->def.definition_spelling = decl_spelling;
|
||||||
func->def.definition_extent = decl_extent;
|
func->def.definition_extent = decl_extent;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
IndexFunc::Declaration declaration;
|
IndexFunc::Declaration declaration;
|
||||||
declaration.spelling = decl_spelling;
|
declaration.spelling = decl_spelling;
|
||||||
declaration.extent = decl_extent;
|
declaration.extent = decl_extent;
|
||||||
declaration.content = GetDocumentContentInRange(param->tu->cx_tu, clang_getCursorExtent(decl->cursor));
|
declaration.content = GetDocumentContentInRange(
|
||||||
|
param->tu->cx_tu, clang_getCursorExtent(decl->cursor));
|
||||||
|
|
||||||
// Add parameters.
|
// Add parameters.
|
||||||
for (clang::Cursor arg : decl_cursor.get_arguments()) {
|
for (clang::Cursor arg : decl_cursor.get_arguments()) {
|
||||||
@ -1096,7 +1119,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
|
|
||||||
// If the name is empty (which is common for parameters), clang
|
// If the name is empty (which is common for parameters), clang
|
||||||
// will report a range with length 1, which is not correct.
|
// will report a range with length 1, which is not correct.
|
||||||
if (param_spelling.start.column == (param_spelling.end.column - 1) &&
|
if (param_spelling.start.column ==
|
||||||
|
(param_spelling.end.column - 1) &&
|
||||||
arg.get_display_name().empty()) {
|
arg.get_display_name().empty()) {
|
||||||
param_spelling.end.column -= 1;
|
param_spelling.end.column -= 1;
|
||||||
}
|
}
|
||||||
@ -1122,7 +1146,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
|
|
||||||
// Build detailed name. The type desc looks like void (void *). We
|
// Build detailed name. The type desc looks like void (void *). We
|
||||||
// insert the qualified name before the first '('.
|
// insert the qualified name before the first '('.
|
||||||
std::string qualified_name = ns->QualifiedName(decl->semanticContainer, func->def.short_name);
|
std::string qualified_name =
|
||||||
|
ns->QualifiedName(decl->semanticContainer, func->def.short_name);
|
||||||
std::string type_desc = decl_cursor.get_type_description();
|
std::string type_desc = decl_cursor.get_type_description();
|
||||||
size_t offset = type_desc.find('(');
|
size_t offset = type_desc.find('(');
|
||||||
type_desc.insert(offset, qualified_name);
|
type_desc.insert(offset, qualified_name);
|
||||||
@ -1142,7 +1167,7 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
UniqueAdd(declaring_type_def->uses, decl_spelling);
|
UniqueAdd(declaring_type_def->uses, decl_spelling);
|
||||||
if (decl->entityInfo->kind == CXIdxEntity_CXXDestructor) {
|
if (decl->entityInfo->kind == CXIdxEntity_CXXDestructor) {
|
||||||
Range dtor_type_range = decl_spelling;
|
Range dtor_type_range = decl_spelling;
|
||||||
dtor_type_range.start.column += 1; // Don't count the leading ~
|
dtor_type_range.start.column += 1; // Don't count the leading ~
|
||||||
UniqueAdd(declaring_type_def->uses, dtor_type_range);
|
UniqueAdd(declaring_type_def->uses, dtor_type_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1155,12 +1180,13 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
CXCursor* overridden;
|
CXCursor* overridden;
|
||||||
unsigned int num_overridden;
|
unsigned int num_overridden;
|
||||||
clang_getOverriddenCursors(decl->cursor, &overridden,
|
clang_getOverriddenCursors(decl->cursor, &overridden,
|
||||||
&num_overridden);
|
&num_overridden);
|
||||||
|
|
||||||
// FIXME if it ever shows up. Methods should only ever have 1 base
|
// FIXME if it ever shows up. Methods should only ever have 1 base
|
||||||
// type, though.
|
// type, though.
|
||||||
if (num_overridden > 1)
|
if (num_overridden > 1)
|
||||||
std::cerr << "[indexer]: warning: multiple base overrides for " << func->def.detailed_name << std::endl;
|
std::cerr << "[indexer]: warning: multiple base overrides for "
|
||||||
|
<< func->def.detailed_name << std::endl;
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_overridden; ++i) {
|
for (unsigned i = 0; i < num_overridden; ++i) {
|
||||||
clang::Cursor parent = overridden[i];
|
clang::Cursor parent = overridden[i];
|
||||||
@ -1185,9 +1211,8 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// Note we want to fetch the first TypeRef. Running
|
// Note we want to fetch the first TypeRef. Running
|
||||||
// ResolveCursorType(decl->cursor) would return
|
// ResolveCursorType(decl->cursor) would return
|
||||||
// the type of the typedef/using, not the type of the referenced type.
|
// the type of the typedef/using, not the type of the referenced type.
|
||||||
optional<IndexTypeId> alias_of =
|
optional<IndexTypeId> alias_of = AddDeclTypeUsages(
|
||||||
AddDeclTypeUsages(db, decl->cursor,
|
db, decl->cursor, decl->semanticContainer, decl->lexicalContainer);
|
||||||
decl->semanticContainer, decl->lexicalContainer);
|
|
||||||
|
|
||||||
IndexTypeId type_id = db->ToTypeId(decl->entityInfo->USR);
|
IndexTypeId type_id = db->ToTypeId(decl->entityInfo->USR);
|
||||||
IndexType* type = db->Resolve(type_id);
|
IndexType* type = db->Resolve(type_id);
|
||||||
@ -1254,15 +1279,14 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
for (unsigned int i = 0; i < class_info->numBases; ++i) {
|
for (unsigned int i = 0; i < class_info->numBases; ++i) {
|
||||||
const CXIdxBaseClassInfo* base_class = class_info->bases[i];
|
const CXIdxBaseClassInfo* base_class = class_info->bases[i];
|
||||||
|
|
||||||
AddDeclTypeUsages(db, base_class->cursor,
|
AddDeclTypeUsages(db, base_class->cursor, decl->semanticContainer,
|
||||||
decl->semanticContainer, decl->lexicalContainer);
|
decl->lexicalContainer);
|
||||||
optional<IndexTypeId> parent_type_id =
|
optional<IndexTypeId> parent_type_id =
|
||||||
ResolveToDeclarationType(db, base_class->cursor);
|
ResolveToDeclarationType(db, base_class->cursor);
|
||||||
// type_def ptr could be invalidated by ResolveToDeclarationType.
|
// type_def ptr could be invalidated by ResolveToDeclarationType.
|
||||||
type = db->Resolve(type_id);
|
type = db->Resolve(type_id);
|
||||||
if (parent_type_id) {
|
if (parent_type_id) {
|
||||||
IndexType* parent_type_def =
|
IndexType* parent_type_def = db->Resolve(parent_type_id.value());
|
||||||
db->Resolve(parent_type_id.value());
|
|
||||||
parent_type_def->derived.push_back(type_id);
|
parent_type_def->derived.push_back(type_id);
|
||||||
type->def.parents.push_back(parent_type_id.value());
|
type->def.parents.push_back(parent_type_id.value());
|
||||||
}
|
}
|
||||||
@ -1272,11 +1296,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr
|
std::cerr << "!! Unhandled indexDeclaration: "
|
||||||
<< "!! Unhandled indexDeclaration: "
|
<< clang::Cursor(decl->cursor).ToString() << " at "
|
||||||
<< clang::Cursor(decl->cursor).ToString() << " at "
|
<< ResolveSpelling(decl->cursor).start.ToString() << std::endl;
|
||||||
<< ResolveSpelling(decl->cursor).start.ToString()
|
|
||||||
<< std::endl;
|
|
||||||
std::cerr << " entityInfo->kind = " << decl->entityInfo->kind
|
std::cerr << " entityInfo->kind = " << decl->entityInfo->kind
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cerr << " entityInfo->USR = " << decl->entityInfo->USR
|
std::cerr << " entityInfo->USR = " << decl->entityInfo->USR
|
||||||
@ -1367,20 +1389,24 @@ bool IsFunctionCallContext(CXCursorKind kind) {
|
|||||||
void indexEntityReference(CXClientData client_data,
|
void indexEntityReference(CXClientData client_data,
|
||||||
const CXIdxEntityRefInfo* ref) {
|
const CXIdxEntityRefInfo* ref) {
|
||||||
// Don't index references from or to system headers.
|
// Don't index references from or to system headers.
|
||||||
if (clang_Location_isInSystemHeader(clang_indexLoc_getCXSourceLocation(ref->loc)) ||
|
if (clang_Location_isInSystemHeader(
|
||||||
clang_Location_isInSystemHeader(clang_getCursorLocation(ref->referencedEntity->cursor)))
|
clang_indexLoc_getCXSourceLocation(ref->loc)) ||
|
||||||
|
clang_Location_isInSystemHeader(
|
||||||
|
clang_getCursorLocation(ref->referencedEntity->cursor)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//assert(AreEqualLocations(ref->loc, ref->cursor));
|
// assert(AreEqualLocations(ref->loc, ref->cursor));
|
||||||
|
|
||||||
// if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref->cursor)) ||
|
// if (clang_Location_isInSystemHeader(clang_getCursorLocation(ref->cursor))
|
||||||
// clang_Location_isInSystemHeader(
|
// ||
|
||||||
// clang_getCursorLocation(ref->referencedEntity->cursor)))
|
// clang_Location_isInSystemHeader(
|
||||||
// return;
|
// clang_getCursorLocation(ref->referencedEntity->cursor)))
|
||||||
|
// return;
|
||||||
|
|
||||||
// TODO: Use clang_getFileUniqueID
|
// TODO: Use clang_getFileUniqueID
|
||||||
CXFile file;
|
CXFile file;
|
||||||
clang_getSpellingLocation(clang_indexLoc_getCXSourceLocation(ref->loc), &file, nullptr, nullptr, nullptr);
|
clang_getSpellingLocation(clang_indexLoc_getCXSourceLocation(ref->loc), &file,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
IndexParam* param = static_cast<IndexParam*>(client_data);
|
IndexParam* param = static_cast<IndexParam*>(client_data);
|
||||||
IndexFile* db = ConsumeFile(param, file);
|
IndexFile* db = ConsumeFile(param, file);
|
||||||
if (!db)
|
if (!db)
|
||||||
@ -1390,17 +1416,18 @@ void indexEntityReference(CXClientData client_data,
|
|||||||
// ref->loc mainFile=1
|
// ref->loc mainFile=1
|
||||||
// ref->referencedEntity mainFile=1
|
// ref->referencedEntity mainFile=1
|
||||||
//
|
//
|
||||||
// Regardless, we need to do more advanced location processing to handle multiple output IndexFile instances.
|
// Regardless, we need to do more advanced location processing to handle
|
||||||
//bool mainFile = clang_Location_isFromMainFile(clang_indexLoc_getCXSourceLocation(ref->loc));
|
// multiple output IndexFile instances.
|
||||||
//Range loc_spelling = param->db->id_cache.ForceResolveSpelling(ref->cursor, false /*interesting*/);
|
// bool mainFile =
|
||||||
//std::cerr << "mainFile: " << mainFile << ", loc: " << loc_spelling.ToString() << std::endl;
|
// clang_Location_isFromMainFile(clang_indexLoc_getCXSourceLocation(ref->loc));
|
||||||
|
// Range loc_spelling = param->db->id_cache.ForceResolveSpelling(ref->cursor,
|
||||||
|
// false /*interesting*/); std::cerr << "mainFile: " << mainFile << ", loc: "
|
||||||
|
// << loc_spelling.ToString() << std::endl;
|
||||||
|
|
||||||
// Don't index references that are not from the main file.
|
// Don't index references that are not from the main file.
|
||||||
//if (!clang_Location_isFromMainFile(clang_getCursorLocation(ref->cursor)))
|
// if (!clang_Location_isFromMainFile(clang_getCursorLocation(ref->cursor)))
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
clang::Cursor cursor(ref->cursor);
|
clang::Cursor cursor(ref->cursor);
|
||||||
|
|
||||||
// std::cerr << "REF kind=" << ref->referencedEntity->kind << " at " <<
|
// std::cerr << "REF kind=" << ref->referencedEntity->kind << " at " <<
|
||||||
@ -1453,8 +1480,10 @@ void indexEntityReference(CXClientData client_data,
|
|||||||
// libclang doesn't provide a nice api to check if the given function
|
// libclang doesn't provide a nice api to check if the given function
|
||||||
// call is implicit. ref->kind should probably work (it's either direct
|
// call is implicit. ref->kind should probably work (it's either direct
|
||||||
// or implicit), but libclang only supports implicit for objective-c.
|
// or implicit), but libclang only supports implicit for objective-c.
|
||||||
bool is_implicit = CanBeCalledImplicitly(ref->referencedEntity->kind) &&
|
bool is_implicit =
|
||||||
!CursorSpellingContainsString(ref->cursor, param->tu->cx_tu, called->def.short_name);
|
CanBeCalledImplicitly(ref->referencedEntity->kind) &&
|
||||||
|
!CursorSpellingContainsString(ref->cursor, param->tu->cx_tu,
|
||||||
|
called->def.short_name);
|
||||||
|
|
||||||
if (IsFunctionCallContext(ref->container->cursor.kind)) {
|
if (IsFunctionCallContext(ref->container->cursor.kind)) {
|
||||||
IndexFuncId caller_id = db->ToFuncId(ref->container->cursor);
|
IndexFuncId caller_id = db->ToFuncId(ref->container->cursor);
|
||||||
@ -1462,8 +1491,10 @@ void indexEntityReference(CXClientData client_data,
|
|||||||
// Calling db->ToFuncId invalidates the FuncDef* ptrs.
|
// Calling db->ToFuncId invalidates the FuncDef* ptrs.
|
||||||
called = db->Resolve(called_id);
|
called = db->Resolve(called_id);
|
||||||
|
|
||||||
AddFuncRef(&caller->def.callees, IndexFuncRef(called_id, loc_spelling, is_implicit));
|
AddFuncRef(&caller->def.callees,
|
||||||
AddFuncRef(&called->callers, IndexFuncRef(caller_id, loc_spelling, is_implicit));
|
IndexFuncRef(called_id, loc_spelling, is_implicit));
|
||||||
|
AddFuncRef(&called->callers,
|
||||||
|
IndexFuncRef(caller_id, loc_spelling, is_implicit));
|
||||||
} else {
|
} else {
|
||||||
AddFuncRef(&called->callers, IndexFuncRef(loc_spelling, is_implicit));
|
AddFuncRef(&called->callers, IndexFuncRef(loc_spelling, is_implicit));
|
||||||
}
|
}
|
||||||
@ -1478,7 +1509,8 @@ void indexEntityReference(CXClientData client_data,
|
|||||||
case CXIdxEntity_Struct:
|
case CXIdxEntity_Struct:
|
||||||
case CXIdxEntity_CXXClass: {
|
case CXIdxEntity_CXXClass: {
|
||||||
clang::Cursor referenced_cursor = ref->referencedEntity->cursor;
|
clang::Cursor referenced_cursor = ref->referencedEntity->cursor;
|
||||||
referenced_cursor = referenced_cursor.template_specialization_to_template_definition();
|
referenced_cursor =
|
||||||
|
referenced_cursor.template_specialization_to_template_definition();
|
||||||
IndexTypeId referenced_id = db->ToTypeId(referenced_cursor.get_usr());
|
IndexTypeId referenced_id = db->ToTypeId(referenced_cursor.get_usr());
|
||||||
|
|
||||||
IndexType* referenced = db->Resolve(referenced_id);
|
IndexType* referenced = db->Resolve(referenced_id);
|
||||||
@ -1503,20 +1535,16 @@ void indexEntityReference(CXClientData client_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cerr
|
std::cerr << "!! Unhandled indexEntityReference: " << cursor.ToString()
|
||||||
<< "!! Unhandled indexEntityReference: " << cursor.ToString()
|
<< " at " << ResolveSpelling(ref->cursor).start.ToString()
|
||||||
<< " at "
|
<< std::endl;
|
||||||
<< ResolveSpelling(ref->cursor).start.ToString()
|
|
||||||
<< std::endl;
|
|
||||||
std::cerr << " ref->referencedEntity->kind = "
|
std::cerr << " ref->referencedEntity->kind = "
|
||||||
<< ref->referencedEntity->kind << std::endl;
|
<< ref->referencedEntity->kind << std::endl;
|
||||||
if (ref->parentEntity)
|
if (ref->parentEntity)
|
||||||
std::cerr << " ref->parentEntity->kind = "
|
std::cerr << " ref->parentEntity->kind = "
|
||||||
<< ref->parentEntity->kind << std::endl;
|
<< ref->parentEntity->kind << std::endl;
|
||||||
std::cerr
|
std::cerr << " ref->loc = "
|
||||||
<< " ref->loc = "
|
<< ResolveSpelling(ref->cursor).start.ToString() << std::endl;
|
||||||
<< ResolveSpelling(ref->cursor).start.ToString()
|
|
||||||
<< std::endl;
|
|
||||||
std::cerr << " ref->kind = " << ref->kind << std::endl;
|
std::cerr << " ref->kind = " << ref->kind << std::endl;
|
||||||
if (ref->parentEntity)
|
if (ref->parentEntity)
|
||||||
std::cerr << " parentEntity = "
|
std::cerr << " parentEntity = "
|
||||||
@ -1563,17 +1591,18 @@ void indexEntityReference(CXClientData client_data,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
FileContents::FileContents(const std::string& path, const std::string& content) : path(path), content(content) {}
|
FileContents::FileContents(const std::string& path, const std::string& content)
|
||||||
|
: path(path), content(content) {}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<IndexFile>> Parse(
|
std::vector<std::unique_ptr<IndexFile>> Parse(
|
||||||
Config* config, FileConsumer::SharedState* file_consumer_shared,
|
Config* config,
|
||||||
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
std::string file,
|
std::string file,
|
||||||
std::vector<std::string> args,
|
std::vector<std::string> args,
|
||||||
std::vector<FileContents> file_contents,
|
std::vector<FileContents> file_contents,
|
||||||
PerformanceImportFile* perf,
|
PerformanceImportFile* perf,
|
||||||
clang::Index* index,
|
clang::Index* index,
|
||||||
bool dump_ast) {
|
bool dump_ast) {
|
||||||
|
|
||||||
if (!config->enableIndexing)
|
if (!config->enableIndexing)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -1590,9 +1619,12 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
|
|||||||
unsaved_files.push_back(unsaved);
|
unsaved_files.push_back(unsaved);
|
||||||
}
|
}
|
||||||
|
|
||||||
clang::TranslationUnit tu(index, file, args, unsaved_files, CXTranslationUnit_KeepGoing | CXTranslationUnit_DetailedPreprocessingRecord);
|
clang::TranslationUnit tu(index, file, args, unsaved_files,
|
||||||
|
CXTranslationUnit_KeepGoing |
|
||||||
|
CXTranslationUnit_DetailedPreprocessingRecord);
|
||||||
if (tu.did_fail) {
|
if (tu.did_fail) {
|
||||||
std::cerr << "!! Failed creating translation unit for " << file << std::endl;
|
std::cerr << "!! Failed creating translation unit for " << file
|
||||||
|
<< std::endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1601,12 +1633,10 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
|
|||||||
if (dump_ast)
|
if (dump_ast)
|
||||||
Dump(tu.document_cursor());
|
Dump(tu.document_cursor());
|
||||||
|
|
||||||
|
IndexerCallbacks callbacks[] = {{&abortQuery, &diagnostic, &enteredMainFile,
|
||||||
IndexerCallbacks callbacks[] = {
|
&ppIncludedFile, &importedASTFile,
|
||||||
{&abortQuery, &diagnostic, &enteredMainFile, &ppIncludedFile,
|
&startedTranslationUnit, &indexDeclaration,
|
||||||
&importedASTFile, &startedTranslationUnit, &indexDeclaration,
|
&indexEntityReference}};
|
||||||
&indexEntityReference}
|
|
||||||
};
|
|
||||||
|
|
||||||
FileConsumer file_consumer(file_consumer_shared, file);
|
FileConsumer file_consumer(file_consumer_shared, file);
|
||||||
IndexParam param(&tu, &file_consumer);
|
IndexParam param(&tu, &file_consumer);
|
||||||
@ -1617,16 +1647,19 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
|
|||||||
CXFile cx_file = clang_getFile(tu.cx_tu, file.c_str());
|
CXFile cx_file = clang_getFile(tu.cx_tu, file.c_str());
|
||||||
param.primary_file = ConsumeFile(¶m, cx_file);
|
param.primary_file = ConsumeFile(¶m, cx_file);
|
||||||
|
|
||||||
//std::cerr << "!! [START] Indexing " << file << std::endl;
|
// std::cerr << "!! [START] Indexing " << file << std::endl;
|
||||||
CXIndexAction index_action = clang_IndexAction_create(index->cx_index);
|
CXIndexAction index_action = clang_IndexAction_create(index->cx_index);
|
||||||
clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks),
|
clang_indexTranslationUnit(index_action, ¶m, callbacks, sizeof(callbacks),
|
||||||
CXIndexOpt_IndexFunctionLocalSymbols | CXIndexOpt_SkipParsedBodiesInSession | CXIndexOpt_IndexImplicitTemplateInstantiations,
|
CXIndexOpt_IndexFunctionLocalSymbols |
|
||||||
|
CXIndexOpt_SkipParsedBodiesInSession |
|
||||||
|
CXIndexOpt_IndexImplicitTemplateInstantiations,
|
||||||
tu.cx_tu);
|
tu.cx_tu);
|
||||||
|
|
||||||
clang_IndexAction_dispose(index_action);
|
clang_IndexAction_dispose(index_action);
|
||||||
//std::cerr << "!! [END] Indexing " << file << std::endl;
|
// std::cerr << "!! [END] Indexing " << file << std::endl;
|
||||||
|
|
||||||
tu.document_cursor().VisitChildren(&VisitMacroDefinitionAndExpansions, ¶m);
|
tu.document_cursor().VisitChildren(&VisitMacroDefinitionAndExpansions,
|
||||||
|
¶m);
|
||||||
|
|
||||||
perf->index_build = timer.ElapsedMicrosecondsAndReset();
|
perf->index_build = timer.ElapsedMicrosecondsAndReset();
|
||||||
|
|
||||||
@ -1655,7 +1688,6 @@ std::vector<std::unique_ptr<IndexFile>> Parse(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void IndexInit() {
|
void IndexInit() {
|
||||||
clang_enableStackTraces();
|
clang_enableStackTraces();
|
||||||
clang_toggleCrashRecovery(1);
|
clang_toggleCrashRecovery(1);
|
||||||
|
103
src/indexer.h
103
src/indexer.h
@ -1,28 +1,31 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "file_consumer.h"
|
#include "file_consumer.h"
|
||||||
#include "position.h"
|
|
||||||
#include "serializer.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "language_server_api.h"
|
#include "language_server_api.h"
|
||||||
#include "libclangmm/Index.h"
|
#include "libclangmm/Index.h"
|
||||||
#include "libclangmm/Utility.h"
|
#include "libclangmm/Utility.h"
|
||||||
#include "performance.h"
|
#include "performance.h"
|
||||||
|
#include "position.h"
|
||||||
|
#include "serializer.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
#include <rapidjson/writer.h>
|
#include <rapidjson/document.h>
|
||||||
#include <rapidjson/prettywriter.h>
|
#include <rapidjson/prettywriter.h>
|
||||||
#include <rapidjson/stringbuffer.h>
|
#include <rapidjson/stringbuffer.h>
|
||||||
#include <rapidjson/document.h>
|
#include <rapidjson/writer.h>
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
struct IndexType;
|
struct IndexType;
|
||||||
struct IndexFunc;
|
struct IndexFunc;
|
||||||
struct IndexVar;
|
struct IndexVar;
|
||||||
@ -49,7 +52,7 @@ template <typename T>
|
|||||||
struct hash<Id<T>> {
|
struct hash<Id<T>> {
|
||||||
size_t operator()(const Id<T>& k) const { return hash<size_t>()(k.id); }
|
size_t operator()(const Id<T>& k) const { return hash<size_t>()(k.id); }
|
||||||
};
|
};
|
||||||
}
|
} // namespace std
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool operator==(const Id<T>& a, const Id<T>& b) {
|
bool operator==(const Id<T>& a, const Id<T>& b) {
|
||||||
@ -61,11 +64,11 @@ bool operator!=(const Id<T>& a, const Id<T>& b) {
|
|||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Reflect(Reader& visitor, Id<T>& id) {
|
void Reflect(Reader& visitor, Id<T>& id) {
|
||||||
id.id = visitor.GetUint64();
|
id.id = visitor.GetUint64();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Reflect(Writer& visitor, Id<T>& value) {
|
void Reflect(Writer& visitor, Id<T>& value) {
|
||||||
visitor.Uint64(value.id);
|
visitor.Uint64(value.id);
|
||||||
}
|
}
|
||||||
@ -76,7 +79,6 @@ using IndexVarId = Id<IndexVar>;
|
|||||||
|
|
||||||
struct IdCache;
|
struct IdCache;
|
||||||
|
|
||||||
|
|
||||||
struct IndexFuncRef {
|
struct IndexFuncRef {
|
||||||
// NOTE: id can be -1 if the function call is not coming from a function.
|
// NOTE: id can be -1 if the function call is not coming from a function.
|
||||||
IndexFuncId id;
|
IndexFuncId id;
|
||||||
@ -85,19 +87,25 @@ struct IndexFuncRef {
|
|||||||
|
|
||||||
IndexFuncRef() {} // For serialization.
|
IndexFuncRef() {} // For serialization.
|
||||||
|
|
||||||
IndexFuncRef(IndexFuncId id, Range loc, bool is_implicit) : id(id), loc(loc), is_implicit(is_implicit) {}
|
IndexFuncRef(IndexFuncId id, Range loc, bool is_implicit)
|
||||||
IndexFuncRef(Range loc, bool is_implicit) : id(IndexFuncId((size_t)-1)), loc(loc), is_implicit(is_implicit) {}
|
: id(id), loc(loc), is_implicit(is_implicit) {}
|
||||||
|
IndexFuncRef(Range loc, bool is_implicit)
|
||||||
|
: id(IndexFuncId((size_t)-1)), loc(loc), is_implicit(is_implicit) {}
|
||||||
|
|
||||||
inline bool operator==(const IndexFuncRef& other) {
|
inline bool operator==(const IndexFuncRef& other) {
|
||||||
return id == other.id && loc == other.loc && is_implicit == other.is_implicit;
|
return id == other.id && loc == other.loc &&
|
||||||
|
is_implicit == other.is_implicit;
|
||||||
|
}
|
||||||
|
inline bool operator!=(const IndexFuncRef& other) {
|
||||||
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
inline bool operator!=(const IndexFuncRef& other) { return !(*this == other); }
|
|
||||||
inline bool operator<(const IndexFuncRef& other) const {
|
inline bool operator<(const IndexFuncRef& other) const {
|
||||||
if (id < other.id)
|
if (id < other.id)
|
||||||
return true;
|
return true;
|
||||||
if (id == other.id && loc < other.loc)
|
if (id == other.id && loc < other.loc)
|
||||||
return true;
|
return true;
|
||||||
return id == other.id && loc == other.loc && is_implicit < other.is_implicit;
|
return id == other.id && loc == other.loc &&
|
||||||
|
is_implicit < other.is_implicit;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,10 +133,9 @@ inline void Reflect(Writer& visitor, IndexFuncRef& value) {
|
|||||||
|
|
||||||
if (value.is_implicit)
|
if (value.is_implicit)
|
||||||
s += "~";
|
s += "~";
|
||||||
if (value.id.id == -1) { // id.id is unsigned, special case 0 value
|
if (value.id.id == -1) { // id.id is unsigned, special case 0 value
|
||||||
s += "-1";
|
s += "-1";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
s += std::to_string(value.id.id);
|
s += std::to_string(value.id.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,10 +143,7 @@ inline void Reflect(Writer& visitor, IndexFuncRef& value) {
|
|||||||
visitor.String(s.c_str());
|
visitor.String(s.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TypeId,
|
template <typename TypeId, typename FuncId, typename VarId, typename Range>
|
||||||
typename FuncId,
|
|
||||||
typename VarId,
|
|
||||||
typename Range>
|
|
||||||
struct TypeDefDefinitionData {
|
struct TypeDefDefinitionData {
|
||||||
// General metadata.
|
// General metadata.
|
||||||
std::string usr;
|
std::string usr;
|
||||||
@ -173,19 +177,18 @@ struct TypeDefDefinitionData {
|
|||||||
TypeDefDefinitionData() {} // For reflection.
|
TypeDefDefinitionData() {} // For reflection.
|
||||||
TypeDefDefinitionData(const std::string& usr) : usr(usr) {}
|
TypeDefDefinitionData(const std::string& usr) : usr(usr) {}
|
||||||
|
|
||||||
bool operator==(const TypeDefDefinitionData<TypeId, FuncId, VarId, Range>&
|
bool operator==(
|
||||||
other) const {
|
const TypeDefDefinitionData<TypeId, FuncId, VarId, Range>& other) const {
|
||||||
return usr == other.usr && short_name == other.short_name &&
|
return usr == other.usr && short_name == other.short_name &&
|
||||||
detailed_name == other.detailed_name &&
|
detailed_name == other.detailed_name &&
|
||||||
definition_spelling == other.definition_spelling &&
|
definition_spelling == other.definition_spelling &&
|
||||||
definition_extent == other.definition_extent &&
|
definition_extent == other.definition_extent &&
|
||||||
alias_of == other.alias_of &&
|
alias_of == other.alias_of && parents == other.parents &&
|
||||||
parents == other.parents && types == other.types &&
|
types == other.types && funcs == other.funcs && vars == other.vars;
|
||||||
funcs == other.funcs && vars == other.vars;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const TypeDefDefinitionData<TypeId, FuncId, VarId, Range>&
|
bool operator!=(
|
||||||
other) const {
|
const TypeDefDefinitionData<TypeId, FuncId, VarId, Range>& other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -211,7 +214,8 @@ void Reflect(TVisitor& visitor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct IndexType {
|
struct IndexType {
|
||||||
using Def = TypeDefDefinitionData<IndexTypeId, IndexFuncId, IndexVarId, Range>;
|
using Def =
|
||||||
|
TypeDefDefinitionData<IndexTypeId, IndexFuncId, IndexVarId, Range>;
|
||||||
Def def;
|
Def def;
|
||||||
|
|
||||||
IndexTypeId id;
|
IndexTypeId id;
|
||||||
@ -268,8 +272,8 @@ struct FuncDefDefinitionData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(
|
bool operator==(
|
||||||
const FuncDefDefinitionData<TypeId, FuncId, VarId, FuncRef, Range>&
|
const FuncDefDefinitionData<TypeId, FuncId, VarId, FuncRef, Range>& other)
|
||||||
other) const {
|
const {
|
||||||
return usr == other.usr && short_name == other.short_name &&
|
return usr == other.usr && short_name == other.short_name &&
|
||||||
detailed_name == other.detailed_name &&
|
detailed_name == other.detailed_name &&
|
||||||
definition_spelling == other.definition_spelling &&
|
definition_spelling == other.definition_spelling &&
|
||||||
@ -278,8 +282,8 @@ struct FuncDefDefinitionData {
|
|||||||
locals == other.locals && callees == other.callees;
|
locals == other.locals && callees == other.callees;
|
||||||
}
|
}
|
||||||
bool operator!=(
|
bool operator!=(
|
||||||
const FuncDefDefinitionData<TypeId, FuncId, VarId, FuncRef, Range>&
|
const FuncDefDefinitionData<TypeId, FuncId, VarId, FuncRef, Range>& other)
|
||||||
other) const {
|
const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -307,7 +311,11 @@ void Reflect(
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct IndexFunc {
|
struct IndexFunc {
|
||||||
using Def = FuncDefDefinitionData<IndexTypeId, IndexFuncId, IndexVarId, IndexFuncRef, Range>;
|
using Def = FuncDefDefinitionData<IndexTypeId,
|
||||||
|
IndexFuncId,
|
||||||
|
IndexVarId,
|
||||||
|
IndexFuncRef,
|
||||||
|
Range>;
|
||||||
Def def;
|
Def def;
|
||||||
|
|
||||||
IndexFuncId id;
|
IndexFuncId id;
|
||||||
@ -346,12 +354,13 @@ struct IndexFunc {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
MAKE_HASHABLE(IndexFunc, t.def.usr);
|
MAKE_HASHABLE(IndexFunc, t.def.usr);
|
||||||
MAKE_REFLECT_STRUCT(IndexFunc::Declaration, spelling, extent, content, param_spellings);
|
MAKE_REFLECT_STRUCT(IndexFunc::Declaration,
|
||||||
|
spelling,
|
||||||
|
extent,
|
||||||
|
content,
|
||||||
|
param_spellings);
|
||||||
|
|
||||||
template <typename TypeId,
|
template <typename TypeId, typename FuncId, typename VarId, typename Range>
|
||||||
typename FuncId,
|
|
||||||
typename VarId,
|
|
||||||
typename Range>
|
|
||||||
struct VarDefDefinitionData {
|
struct VarDefDefinitionData {
|
||||||
// General metadata.
|
// General metadata.
|
||||||
std::string usr;
|
std::string usr;
|
||||||
@ -377,8 +386,8 @@ struct VarDefDefinitionData {
|
|||||||
VarDefDefinitionData() {} // For reflection.
|
VarDefDefinitionData() {} // For reflection.
|
||||||
VarDefDefinitionData(const std::string& usr) : usr(usr) {}
|
VarDefDefinitionData(const std::string& usr) : usr(usr) {}
|
||||||
|
|
||||||
bool operator==(const VarDefDefinitionData<TypeId, FuncId, VarId, Range>&
|
bool operator==(
|
||||||
other) const {
|
const VarDefDefinitionData<TypeId, FuncId, VarId, Range>& other) const {
|
||||||
return usr == other.usr && short_name == other.short_name &&
|
return usr == other.usr && short_name == other.short_name &&
|
||||||
detailed_name == other.detailed_name &&
|
detailed_name == other.detailed_name &&
|
||||||
declaration == other.declaration &&
|
declaration == other.declaration &&
|
||||||
@ -387,8 +396,8 @@ struct VarDefDefinitionData {
|
|||||||
variable_type == other.variable_type &&
|
variable_type == other.variable_type &&
|
||||||
declaring_type == other.declaring_type;
|
declaring_type == other.declaring_type;
|
||||||
}
|
}
|
||||||
bool operator!=(const VarDefDefinitionData<TypeId, FuncId, VarId, Range>&
|
bool operator!=(
|
||||||
other) const {
|
const VarDefDefinitionData<TypeId, FuncId, VarId, Range>& other) const {
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -509,9 +518,11 @@ struct FileContents {
|
|||||||
|
|
||||||
// |import_file| is the cc file which is what gets passed to clang.
|
// |import_file| is the cc file which is what gets passed to clang.
|
||||||
// |desired_index_file| is the (h or cc) file which has actually changed.
|
// |desired_index_file| is the (h or cc) file which has actually changed.
|
||||||
// |dependencies| are the existing dependencies of |import_file| if this is a reparse.
|
// |dependencies| are the existing dependencies of |import_file| if this is a
|
||||||
|
// reparse.
|
||||||
std::vector<std::unique_ptr<IndexFile>> Parse(
|
std::vector<std::unique_ptr<IndexFile>> Parse(
|
||||||
Config* config, FileConsumer::SharedState* file_consumer_shared,
|
Config* config,
|
||||||
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
std::string file,
|
std::string file,
|
||||||
std::vector<std::string> args,
|
std::vector<std::string> args,
|
||||||
std::vector<FileContents> file_contents,
|
std::vector<FileContents> file_contents,
|
||||||
|
149
src/ipc.cc
149
src/ipc.cc
@ -4,88 +4,87 @@
|
|||||||
|
|
||||||
const char* IpcIdToString(IpcId id) {
|
const char* IpcIdToString(IpcId id) {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case IpcId::CancelRequest:
|
case IpcId::CancelRequest:
|
||||||
return "$/cancelRequest";
|
return "$/cancelRequest";
|
||||||
case IpcId::Initialize:
|
case IpcId::Initialize:
|
||||||
return "initialize";
|
return "initialize";
|
||||||
case IpcId::Initialized:
|
case IpcId::Initialized:
|
||||||
return "initialized";
|
return "initialized";
|
||||||
case IpcId::Exit:
|
case IpcId::Exit:
|
||||||
return "exit";
|
return "exit";
|
||||||
case IpcId::TextDocumentDidOpen:
|
case IpcId::TextDocumentDidOpen:
|
||||||
return "textDocument/didOpen";
|
return "textDocument/didOpen";
|
||||||
case IpcId::TextDocumentDidChange:
|
case IpcId::TextDocumentDidChange:
|
||||||
return "textDocument/didChange";
|
return "textDocument/didChange";
|
||||||
case IpcId::TextDocumentDidClose:
|
case IpcId::TextDocumentDidClose:
|
||||||
return "textDocument/didClose";
|
return "textDocument/didClose";
|
||||||
case IpcId::TextDocumentDidSave:
|
case IpcId::TextDocumentDidSave:
|
||||||
return "textDocument/didSave";
|
return "textDocument/didSave";
|
||||||
case IpcId::TextDocumentPublishDiagnostics:
|
case IpcId::TextDocumentPublishDiagnostics:
|
||||||
return "textDocument/publishDiagnostics";
|
return "textDocument/publishDiagnostics";
|
||||||
case IpcId::TextDocumentRename:
|
case IpcId::TextDocumentRename:
|
||||||
return "textDocument/rename";
|
return "textDocument/rename";
|
||||||
case IpcId::TextDocumentCompletion:
|
case IpcId::TextDocumentCompletion:
|
||||||
return "textDocument/completion";
|
return "textDocument/completion";
|
||||||
case IpcId::TextDocumentSignatureHelp:
|
case IpcId::TextDocumentSignatureHelp:
|
||||||
return "textDocument/signatureHelp";
|
return "textDocument/signatureHelp";
|
||||||
case IpcId::TextDocumentDefinition:
|
case IpcId::TextDocumentDefinition:
|
||||||
return "textDocument/definition";
|
return "textDocument/definition";
|
||||||
case IpcId::TextDocumentDocumentHighlight:
|
case IpcId::TextDocumentDocumentHighlight:
|
||||||
return "textDocument/documentHighlight";
|
return "textDocument/documentHighlight";
|
||||||
case IpcId::TextDocumentHover:
|
case IpcId::TextDocumentHover:
|
||||||
return "textDocument/hover";
|
return "textDocument/hover";
|
||||||
case IpcId::TextDocumentReferences:
|
case IpcId::TextDocumentReferences:
|
||||||
return "textDocument/references";
|
return "textDocument/references";
|
||||||
case IpcId::TextDocumentDocumentSymbol:
|
case IpcId::TextDocumentDocumentSymbol:
|
||||||
return "textDocument/documentSymbol";
|
return "textDocument/documentSymbol";
|
||||||
case IpcId::TextDocumentDocumentLink:
|
case IpcId::TextDocumentDocumentLink:
|
||||||
return "textDocument/documentLink";
|
return "textDocument/documentLink";
|
||||||
case IpcId::TextDocumentCodeAction:
|
case IpcId::TextDocumentCodeAction:
|
||||||
return "textDocument/codeAction";
|
return "textDocument/codeAction";
|
||||||
case IpcId::TextDocumentCodeLens:
|
case IpcId::TextDocumentCodeLens:
|
||||||
return "textDocument/codeLens";
|
return "textDocument/codeLens";
|
||||||
case IpcId::CodeLensResolve:
|
case IpcId::CodeLensResolve:
|
||||||
return "codeLens/resolve";
|
return "codeLens/resolve";
|
||||||
case IpcId::WorkspaceSymbol:
|
case IpcId::WorkspaceSymbol:
|
||||||
return "workspace/symbol";
|
return "workspace/symbol";
|
||||||
|
|
||||||
case IpcId::CqueryPublishInactiveRegions:
|
case IpcId::CqueryPublishInactiveRegions:
|
||||||
return "$cquery/publishInactiveRegions";
|
return "$cquery/publishInactiveRegions";
|
||||||
|
|
||||||
case IpcId::CqueryFreshenIndex:
|
case IpcId::CqueryFreshenIndex:
|
||||||
return "$cquery/freshenIndex";
|
return "$cquery/freshenIndex";
|
||||||
case IpcId::CqueryTypeHierarchyTree:
|
case IpcId::CqueryTypeHierarchyTree:
|
||||||
return "$cquery/typeHierarchyTree";
|
return "$cquery/typeHierarchyTree";
|
||||||
case IpcId::CqueryCallTreeInitial:
|
case IpcId::CqueryCallTreeInitial:
|
||||||
return "$cquery/callTreeInitial";
|
return "$cquery/callTreeInitial";
|
||||||
case IpcId::CqueryCallTreeExpand:
|
case IpcId::CqueryCallTreeExpand:
|
||||||
return "$cquery/callTreeExpand";
|
return "$cquery/callTreeExpand";
|
||||||
case IpcId::CqueryVars:
|
case IpcId::CqueryVars:
|
||||||
return "$cquery/vars";
|
return "$cquery/vars";
|
||||||
case IpcId::CqueryCallers:
|
case IpcId::CqueryCallers:
|
||||||
return "$cquery/callers";
|
return "$cquery/callers";
|
||||||
case IpcId::CqueryBase:
|
case IpcId::CqueryBase:
|
||||||
return "$cquery/base";
|
return "$cquery/base";
|
||||||
case IpcId::CqueryDerived:
|
case IpcId::CqueryDerived:
|
||||||
return "$cquery/derived";
|
return "$cquery/derived";
|
||||||
|
|
||||||
case IpcId::Cout:
|
case IpcId::Cout:
|
||||||
return "$cout";
|
return "$cout";
|
||||||
|
|
||||||
case IpcId::CqueryIndexFile:
|
case IpcId::CqueryIndexFile:
|
||||||
return "$cquery/indexFile";
|
return "$cquery/indexFile";
|
||||||
case IpcId::CqueryQueryDbWaitForIdleIndexer:
|
case IpcId::CqueryQueryDbWaitForIdleIndexer:
|
||||||
return "$cquery/queryDbWaitForIdleIndexer";
|
return "$cquery/queryDbWaitForIdleIndexer";
|
||||||
case IpcId::CqueryExitWhenIdle:
|
case IpcId::CqueryExitWhenIdle:
|
||||||
return "$cquery/exitWhenIdle";
|
return "$cquery/exitWhenIdle";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false && "missing IpcId string name");
|
assert(false && "missing IpcId string name");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseIpcMessage::BaseIpcMessage(IpcId method_id)
|
BaseIpcMessage::BaseIpcMessage(IpcId method_id) : method_id(method_id) {}
|
||||||
: method_id(method_id) {}
|
|
||||||
|
|
||||||
BaseIpcMessage::~BaseIpcMessage() = default;
|
BaseIpcMessage::~BaseIpcMessage() = default;
|
20
src/ipc.h
20
src/ipc.h
@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -40,10 +41,10 @@ enum class IpcId : int {
|
|||||||
CqueryCallTreeInitial,
|
CqueryCallTreeInitial,
|
||||||
CqueryCallTreeExpand,
|
CqueryCallTreeExpand,
|
||||||
// These are like DocumentReferences but show different types of data.
|
// These are like DocumentReferences but show different types of data.
|
||||||
CqueryVars, // Show all variables of a type.
|
CqueryVars, // Show all variables of a type.
|
||||||
CqueryCallers, // Show all callers of a function.
|
CqueryCallers, // Show all callers of a function.
|
||||||
CqueryBase, // Show base types/method.
|
CqueryBase, // Show base types/method.
|
||||||
CqueryDerived, // Show all derived types/methods.
|
CqueryDerived, // Show all derived types/methods.
|
||||||
|
|
||||||
// Internal implementation detail.
|
// Internal implementation detail.
|
||||||
Cout,
|
Cout,
|
||||||
@ -88,10 +89,15 @@ struct Ipc_CqueryIndexFile : public IpcMessage<Ipc_CqueryIndexFile> {
|
|||||||
};
|
};
|
||||||
Params params;
|
Params params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryIndexFile::Params, path, args, is_interactive, contents);
|
MAKE_REFLECT_STRUCT(Ipc_CqueryIndexFile::Params,
|
||||||
|
path,
|
||||||
|
args,
|
||||||
|
is_interactive,
|
||||||
|
contents);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryIndexFile, params);
|
MAKE_REFLECT_STRUCT(Ipc_CqueryIndexFile, params);
|
||||||
|
|
||||||
struct Ipc_CqueryQueryDbWaitForIdleIndexer : public IpcMessage<Ipc_CqueryQueryDbWaitForIdleIndexer> {
|
struct Ipc_CqueryQueryDbWaitForIdleIndexer
|
||||||
|
: public IpcMessage<Ipc_CqueryQueryDbWaitForIdleIndexer> {
|
||||||
static constexpr IpcId kIpcId = IpcId::CqueryQueryDbWaitForIdleIndexer;
|
static constexpr IpcId kIpcId = IpcId::CqueryQueryDbWaitForIdleIndexer;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_EMPTY_STRUCT(Ipc_CqueryQueryDbWaitForIdleIndexer);
|
MAKE_REFLECT_EMPTY_STRUCT(Ipc_CqueryQueryDbWaitForIdleIndexer);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
IpcManager* IpcManager::instance_ = nullptr;
|
IpcManager* IpcManager::instance_ = nullptr;
|
||||||
|
|
||||||
// static
|
// static
|
||||||
IpcManager* IpcManager::instance() {
|
IpcManager* IpcManager::instance() {
|
||||||
return instance_;
|
return instance_;
|
||||||
}
|
}
|
||||||
@ -12,8 +12,10 @@ void IpcManager::CreateInstance(MultiQueueWaiter* waiter) {
|
|||||||
instance_ = new IpcManager(waiter);
|
instance_ = new IpcManager(waiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadedQueue<std::unique_ptr<BaseIpcMessage>>* IpcManager::GetThreadedQueue(Destination destination) {
|
ThreadedQueue<std::unique_ptr<BaseIpcMessage>>* IpcManager::GetThreadedQueue(
|
||||||
return destination == Destination::Client ? threaded_queue_for_client_.get() : threaded_queue_for_server_.get();
|
Destination destination) {
|
||||||
|
return destination == Destination::Client ? threaded_queue_for_client_.get()
|
||||||
|
: threaded_queue_for_server_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcManager::SendOutMessageToClient(IpcId id, lsBaseOutMessage& response) {
|
void IpcManager::SendOutMessageToClient(IpcId id, lsBaseOutMessage& response) {
|
||||||
@ -26,15 +28,19 @@ void IpcManager::SendOutMessageToClient(IpcId id, lsBaseOutMessage& response) {
|
|||||||
GetThreadedQueue(Destination::Client)->Enqueue(std::move(out));
|
GetThreadedQueue(Destination::Client)->Enqueue(std::move(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcManager::SendMessage(Destination destination, std::unique_ptr<BaseIpcMessage> message) {
|
void IpcManager::SendMessage(Destination destination,
|
||||||
|
std::unique_ptr<BaseIpcMessage> message) {
|
||||||
GetThreadedQueue(destination)->Enqueue(std::move(message));
|
GetThreadedQueue(destination)->Enqueue(std::move(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<BaseIpcMessage>> IpcManager::GetMessages(Destination destination) {
|
std::vector<std::unique_ptr<BaseIpcMessage>> IpcManager::GetMessages(
|
||||||
|
Destination destination) {
|
||||||
return GetThreadedQueue(destination)->DequeueAll();
|
return GetThreadedQueue(destination)->DequeueAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcManager::IpcManager(MultiQueueWaiter* waiter) {
|
IpcManager::IpcManager(MultiQueueWaiter* waiter) {
|
||||||
threaded_queue_for_client_ = MakeUnique<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>>(waiter);
|
threaded_queue_for_client_ =
|
||||||
threaded_queue_for_server_ = MakeUnique<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>>(waiter);
|
MakeUnique<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>>(waiter);
|
||||||
|
threaded_queue_for_server_ =
|
||||||
|
MakeUnique<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>>(waiter);
|
||||||
}
|
}
|
@ -11,21 +11,24 @@ struct IpcManager {
|
|||||||
static IpcManager* instance();
|
static IpcManager* instance();
|
||||||
static void CreateInstance(MultiQueueWaiter* waiter);
|
static void CreateInstance(MultiQueueWaiter* waiter);
|
||||||
|
|
||||||
std::unique_ptr<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>> threaded_queue_for_client_;
|
std::unique_ptr<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>>
|
||||||
std::unique_ptr<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>> threaded_queue_for_server_;
|
threaded_queue_for_client_;
|
||||||
|
std::unique_ptr<ThreadedQueue<std::unique_ptr<BaseIpcMessage>>>
|
||||||
|
threaded_queue_for_server_;
|
||||||
|
|
||||||
enum class Destination {
|
enum class Destination { Client, Server };
|
||||||
Client, Server
|
|
||||||
};
|
|
||||||
|
|
||||||
ThreadedQueue<std::unique_ptr<BaseIpcMessage>>* GetThreadedQueue(Destination destination);
|
ThreadedQueue<std::unique_ptr<BaseIpcMessage>>* GetThreadedQueue(
|
||||||
|
Destination destination);
|
||||||
|
|
||||||
void SendOutMessageToClient(IpcId id, lsBaseOutMessage& response);
|
void SendOutMessageToClient(IpcId id, lsBaseOutMessage& response);
|
||||||
|
|
||||||
void SendMessage(Destination destination, std::unique_ptr<BaseIpcMessage> message);
|
void SendMessage(Destination destination,
|
||||||
|
std::unique_ptr<BaseIpcMessage> message);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<BaseIpcMessage>> GetMessages(Destination destination);
|
std::vector<std::unique_ptr<BaseIpcMessage>> GetMessages(
|
||||||
|
Destination destination);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IpcManager(MultiQueueWaiter* waiter);
|
IpcManager(MultiQueueWaiter* waiter);
|
||||||
};
|
};
|
||||||
|
@ -8,8 +8,7 @@ void Reflect(Writer& visitor, lsRequestId& value) {
|
|||||||
|
|
||||||
if (value.id0) {
|
if (value.id0) {
|
||||||
Reflect(visitor, value.id0.value());
|
Reflect(visitor, value.id0.value());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Reflect(visitor, value.id1.value());
|
Reflect(visitor, value.id1.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,7 +25,8 @@ void Reflect(Reader& visitor, lsRequestId& id) {
|
|||||||
MessageRegistry* MessageRegistry::instance_ = nullptr;
|
MessageRegistry* MessageRegistry::instance_ = nullptr;
|
||||||
|
|
||||||
// Reads a JsonRpc message. |read| returns the next input character.
|
// Reads a JsonRpc message. |read| returns the next input character.
|
||||||
optional<std::string> ReadJsonRpcContentFrom(std::function<optional<char>()> read) {
|
optional<std::string> ReadJsonRpcContentFrom(
|
||||||
|
std::function<optional<char>()> read) {
|
||||||
// Read the content length. It is terminated by the "\r\n" sequence.
|
// Read the content length. It is terminated by the "\r\n" sequence.
|
||||||
int exit_seq = 0;
|
int exit_seq = 0;
|
||||||
std::string stringified_content_length;
|
std::string stringified_content_length;
|
||||||
@ -38,14 +38,17 @@ optional<std::string> ReadJsonRpcContentFrom(std::function<optional<char>()> rea
|
|||||||
}
|
}
|
||||||
char c = *opt_c;
|
char c = *opt_c;
|
||||||
|
|
||||||
if (exit_seq == 0 && c == '\r') ++exit_seq;
|
if (exit_seq == 0 && c == '\r')
|
||||||
if (exit_seq == 1 && c == '\n') break;
|
++exit_seq;
|
||||||
|
if (exit_seq == 1 && c == '\n')
|
||||||
|
break;
|
||||||
|
|
||||||
stringified_content_length += c;
|
stringified_content_length += c;
|
||||||
}
|
}
|
||||||
const char* kContentLengthStart = "Content-Length: ";
|
const char* kContentLengthStart = "Content-Length: ";
|
||||||
assert(StartsWith(stringified_content_length, kContentLengthStart));
|
assert(StartsWith(stringified_content_length, kContentLengthStart));
|
||||||
int content_length = atoi(stringified_content_length.c_str() + strlen(kContentLengthStart));
|
int content_length =
|
||||||
|
atoi(stringified_content_length.c_str() + strlen(kContentLengthStart));
|
||||||
|
|
||||||
// There is always a "\r\n" sequence before the actual content.
|
// There is always a "\r\n" sequence before the actual content.
|
||||||
auto expect_char = [&](char expected) {
|
auto expect_char = [&](char expected) {
|
||||||
@ -74,8 +77,8 @@ optional<std::string> ReadJsonRpcContentFrom(std::function<optional<char>()> rea
|
|||||||
|
|
||||||
TEST_SUITE("FindIncludeLine");
|
TEST_SUITE("FindIncludeLine");
|
||||||
|
|
||||||
std::function<optional<char>()>
|
std::function<optional<char>()> MakeContentReader(std::string* content,
|
||||||
MakeContentReader(std::string* content, bool can_be_empty) {
|
bool can_be_empty) {
|
||||||
return [content, can_be_empty]() -> optional<char> {
|
return [content, can_be_empty]() -> optional<char> {
|
||||||
if (!can_be_empty)
|
if (!can_be_empty)
|
||||||
REQUIRE(!content->empty());
|
REQUIRE(!content->empty());
|
||||||
@ -106,7 +109,8 @@ TEST_CASE("ReadContentFromSource") {
|
|||||||
|
|
||||||
REQUIRE(parse_incorrect("ggg") == optional<std::string>());
|
REQUIRE(parse_incorrect("ggg") == optional<std::string>());
|
||||||
REQUIRE(parse_incorrect("Content-Length: 0\r\n") == optional<std::string>());
|
REQUIRE(parse_incorrect("Content-Length: 0\r\n") == optional<std::string>());
|
||||||
REQUIRE(parse_incorrect("Content-Length: 5\r\n\r\nab") == optional<std::string>());
|
REQUIRE(parse_incorrect("Content-Length: 5\r\n\r\nab") ==
|
||||||
|
optional<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
@ -125,7 +129,8 @@ optional<char> ReadCharFromStdinBlocking() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<BaseIpcMessage> MessageRegistry::ReadMessageFromStdin() {
|
std::unique_ptr<BaseIpcMessage> MessageRegistry::ReadMessageFromStdin() {
|
||||||
optional<std::string> content = ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
|
optional<std::string> content =
|
||||||
|
ReadJsonRpcContentFrom(&ReadCharFromStdinBlocking);
|
||||||
if (!content) {
|
if (!content) {
|
||||||
LOG_S(FATAL) << "Failed to read JsonRpc input; exiting";
|
LOG_S(FATAL) << "Failed to read JsonRpc input; exiting";
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -139,7 +144,8 @@ std::unique_ptr<BaseIpcMessage> MessageRegistry::ReadMessageFromStdin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<BaseIpcMessage> MessageRegistry::Parse(Reader& visitor) {
|
std::unique_ptr<BaseIpcMessage> MessageRegistry::Parse(Reader& visitor) {
|
||||||
if (!visitor.HasMember("jsonrpc") || std::string(visitor["jsonrpc"].GetString()) != "2.0") {
|
if (!visitor.HasMember("jsonrpc") ||
|
||||||
|
std::string(visitor["jsonrpc"].GetString()) != "2.0") {
|
||||||
std::cerr << "Bad or missing jsonrpc version" << std::endl;
|
std::cerr << "Bad or missing jsonrpc version" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -148,7 +154,8 @@ std::unique_ptr<BaseIpcMessage> MessageRegistry::Parse(Reader& visitor) {
|
|||||||
ReflectMember(visitor, "method", method);
|
ReflectMember(visitor, "method", method);
|
||||||
|
|
||||||
if (allocators.find(method) == allocators.end()) {
|
if (allocators.find(method) == allocators.end()) {
|
||||||
LOG_S(ERROR) << "Unable to find registered handler for method \"" << method << "\"" << std::endl;
|
LOG_S(ERROR) << "Unable to find registered handler for method \"" << method
|
||||||
|
<< "\"" << std::endl;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,8 +203,9 @@ void lsDocumentUri::SetPath(const std::string& path) {
|
|||||||
raw_uri = path;
|
raw_uri = path;
|
||||||
|
|
||||||
size_t index = raw_uri.find(":");
|
size_t index = raw_uri.find(":");
|
||||||
if (index == 1) { // widows drive letters must always be 1 char
|
if (index == 1) { // widows drive letters must always be 1 char
|
||||||
raw_uri.replace(raw_uri.begin() + index, raw_uri.begin() + index + 1, "%3A");
|
raw_uri.replace(raw_uri.begin() + index, raw_uri.begin() + index + 1,
|
||||||
|
"%3A");
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_uri = ReplaceAll(raw_uri, " ", "%20");
|
raw_uri = ReplaceAll(raw_uri, " ", "%20");
|
||||||
@ -210,7 +218,7 @@ void lsDocumentUri::SetPath(const std::string& path) {
|
|||||||
#else
|
#else
|
||||||
raw_uri = "file://" + raw_uri;
|
raw_uri = "file://" + raw_uri;
|
||||||
#endif
|
#endif
|
||||||
//std::cerr << "Set uri to " << raw_uri << " from " << path;
|
// std::cerr << "Set uri to " << raw_uri << " from " << path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string lsDocumentUri::GetPath() const {
|
std::string lsDocumentUri::GetPath() const {
|
||||||
@ -242,14 +250,15 @@ std::string lsDocumentUri::GetPath() const {
|
|||||||
std::replace(result.begin(), result.end(), '\\', '/');
|
std::replace(result.begin(), result.end(), '\\', '/');
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
//std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
// std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsPosition::lsPosition() {}
|
lsPosition::lsPosition() {}
|
||||||
lsPosition::lsPosition(int line, int character) : line(line), character(character) {}
|
lsPosition::lsPosition(int line, int character)
|
||||||
|
: line(line), character(character) {}
|
||||||
|
|
||||||
bool lsPosition::operator==(const lsPosition& other) const {
|
bool lsPosition::operator==(const lsPosition& other) const {
|
||||||
return line == other.line && character == other.character;
|
return line == other.line && character == other.character;
|
||||||
@ -267,7 +276,8 @@ bool lsRange::operator==(const lsRange& other) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lsLocation::lsLocation() {}
|
lsLocation::lsLocation() {}
|
||||||
lsLocation::lsLocation(lsDocumentUri uri, lsRange range) : uri(uri), range(range) {}
|
lsLocation::lsLocation(lsDocumentUri uri, lsRange range)
|
||||||
|
: uri(uri), range(range) {}
|
||||||
|
|
||||||
bool lsLocation::operator==(const lsLocation& other) const {
|
bool lsLocation::operator==(const lsLocation& other) const {
|
||||||
return uri == other.uri && range == other.range;
|
return uri == other.uri && range == other.range;
|
||||||
@ -297,15 +307,15 @@ void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) {
|
|||||||
|
|
||||||
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
|
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case lsInitializeParams::lsTrace::Off:
|
case lsInitializeParams::lsTrace::Off:
|
||||||
writer.String("off");
|
writer.String("off");
|
||||||
break;
|
break;
|
||||||
case lsInitializeParams::lsTrace::Messages:
|
case lsInitializeParams::lsTrace::Messages:
|
||||||
writer.String("messages");
|
writer.String("messages");
|
||||||
break;
|
break;
|
||||||
case lsInitializeParams::lsTrace::Verbose:
|
case lsInitializeParams::lsTrace::Verbose:
|
||||||
writer.String("verbose");
|
writer.String("verbose");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
@ -79,10 +79,11 @@ struct MessageRegistry {
|
|||||||
static MessageRegistry* instance_;
|
static MessageRegistry* instance_;
|
||||||
static MessageRegistry* instance();
|
static MessageRegistry* instance();
|
||||||
|
|
||||||
using Allocator = std::function<std::unique_ptr<BaseIpcMessage>(Reader& visitor)>;
|
using Allocator =
|
||||||
|
std::function<std::unique_ptr<BaseIpcMessage>(Reader& visitor)>;
|
||||||
std::unordered_map<std::string, Allocator> allocators;
|
std::unordered_map<std::string, Allocator> allocators;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Register() {
|
void Register() {
|
||||||
std::string method_name = IpcIdToString(T::kIpcId);
|
std::string method_name = IpcIdToString(T::kIpcId);
|
||||||
allocators[method_name] = [](Reader& visitor) {
|
allocators[method_name] = [](Reader& visitor) {
|
||||||
@ -96,13 +97,12 @@ struct MessageRegistry {
|
|||||||
std::unique_ptr<BaseIpcMessage> Parse(Reader& visitor);
|
std::unique_ptr<BaseIpcMessage> Parse(Reader& visitor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct lsBaseOutMessage {
|
struct lsBaseOutMessage {
|
||||||
virtual ~lsBaseOutMessage();
|
virtual ~lsBaseOutMessage();
|
||||||
virtual void Write(std::ostream& out) = 0;
|
virtual void Write(std::ostream& out) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TDerived>
|
template <typename TDerived>
|
||||||
struct lsOutMessage : lsBaseOutMessage {
|
struct lsOutMessage : lsBaseOutMessage {
|
||||||
// All derived types need to reflect on the |jsonrpc| member.
|
// All derived types need to reflect on the |jsonrpc| member.
|
||||||
std::string jsonrpc = "2.0";
|
std::string jsonrpc = "2.0";
|
||||||
@ -115,7 +115,7 @@ struct lsOutMessage : lsBaseOutMessage {
|
|||||||
Reflect(writer, *that);
|
Reflect(writer, *that);
|
||||||
|
|
||||||
out << "Content-Length: " << output.GetSize();
|
out << "Content-Length: " << output.GetSize();
|
||||||
out << (char)13 << char(10) << char(13) << char(10); // CRLFCRLF
|
out << (char)13 << char(10) << char(13) << char(10); // CRLFCRLF
|
||||||
out << output.GetString();
|
out << output.GetString();
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
@ -216,12 +216,11 @@ struct lsDocumentUri {
|
|||||||
};
|
};
|
||||||
MAKE_HASHABLE(lsDocumentUri, t.raw_uri);
|
MAKE_HASHABLE(lsDocumentUri, t.raw_uri);
|
||||||
|
|
||||||
template<typename TVisitor>
|
template <typename TVisitor>
|
||||||
void Reflect(TVisitor& visitor, lsDocumentUri& value) {
|
void Reflect(TVisitor& visitor, lsDocumentUri& value) {
|
||||||
Reflect(visitor, value.raw_uri);
|
Reflect(visitor, value.raw_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct lsPosition {
|
struct lsPosition {
|
||||||
lsPosition();
|
lsPosition();
|
||||||
lsPosition(int line, int character);
|
lsPosition(int line, int character);
|
||||||
@ -291,7 +290,7 @@ struct lsSymbolInformation {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsSymbolInformation, name, kind, location, containerName);
|
MAKE_REFLECT_STRUCT(lsSymbolInformation, name, kind, location, containerName);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
struct lsCommand {
|
struct lsCommand {
|
||||||
// Title of the command (ie, 'save')
|
// Title of the command (ie, 'save')
|
||||||
std::string title;
|
std::string title;
|
||||||
@ -302,7 +301,7 @@ struct lsCommand {
|
|||||||
// MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY.
|
// MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY.
|
||||||
T arguments;
|
T arguments;
|
||||||
};
|
};
|
||||||
template<typename TVisitor, typename T>
|
template <typename TVisitor, typename T>
|
||||||
void Reflect(TVisitor& visitor, lsCommand<T>& value) {
|
void Reflect(TVisitor& visitor, lsCommand<T>& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER(title);
|
REFLECT_MEMBER(title);
|
||||||
@ -311,7 +310,7 @@ void Reflect(TVisitor& visitor, lsCommand<T>& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TData, typename TCommandArguments>
|
template <typename TData, typename TCommandArguments>
|
||||||
struct lsCodeLens {
|
struct lsCodeLens {
|
||||||
// The range in which this code lens is valid. Should only span a single line.
|
// The range in which this code lens is valid. Should only span a single line.
|
||||||
lsRange range;
|
lsRange range;
|
||||||
@ -321,7 +320,7 @@ struct lsCodeLens {
|
|||||||
// a code lens and a code lens resolve request.
|
// a code lens and a code lens resolve request.
|
||||||
TData data;
|
TData data;
|
||||||
};
|
};
|
||||||
template<typename TVisitor, typename TData, typename TCommandArguments>
|
template <typename TVisitor, typename TData, typename TCommandArguments>
|
||||||
void Reflect(TVisitor& visitor, lsCodeLens<TData, TCommandArguments>& value) {
|
void Reflect(TVisitor& visitor, lsCodeLens<TData, TCommandArguments>& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER(range);
|
REFLECT_MEMBER(range);
|
||||||
@ -377,7 +376,8 @@ enum class lsInsertTextFormat {
|
|||||||
// the end of the snippet. Placeholders with equal identifiers are linked,
|
// the end of the snippet. Placeholders with equal identifiers are linked,
|
||||||
// that is typing in one will update others too.
|
// that is typing in one will update others too.
|
||||||
//
|
//
|
||||||
// See also: https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
|
// See also:
|
||||||
|
// https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md
|
||||||
Snippet = 2
|
Snippet = 2
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_TYPE_PROXY(lsInsertTextFormat, int);
|
MAKE_REFLECT_TYPE_PROXY(lsInsertTextFormat, int);
|
||||||
@ -406,7 +406,8 @@ enum class lsCompletionItemKind {
|
|||||||
MAKE_REFLECT_TYPE_PROXY(lsCompletionItemKind, int);
|
MAKE_REFLECT_TYPE_PROXY(lsCompletionItemKind, int);
|
||||||
|
|
||||||
struct lsCompletionItem {
|
struct lsCompletionItem {
|
||||||
// A set of function parameters. Used internally for signature help. Not sent to vscode.
|
// A set of function parameters. Used internally for signature help. Not sent
|
||||||
|
// to vscode.
|
||||||
std::vector<std::string> parameters_;
|
std::vector<std::string> parameters_;
|
||||||
|
|
||||||
// The label of this completion item. By default
|
// The label of this completion item. By default
|
||||||
@ -431,21 +432,21 @@ struct lsCompletionItem {
|
|||||||
|
|
||||||
// A string that should be used when filtering a set of
|
// A string that should be used when filtering a set of
|
||||||
// completion items. When `falsy` the label is used.
|
// completion items. When `falsy` the label is used.
|
||||||
//std::string filterText;
|
// std::string filterText;
|
||||||
|
|
||||||
// A string that should be inserted a document when selecting
|
// A string that should be inserted a document when selecting
|
||||||
// this completion. When `falsy` the label is used.
|
// this completion. When `falsy` the label is used.
|
||||||
std::string insertText;
|
std::string insertText;
|
||||||
|
|
||||||
// The format of the insert text. The format applies to both the `insertText` property
|
// The format of the insert text. The format applies to both the `insertText`
|
||||||
// and the `newText` property of a provided `textEdit`.
|
// property and the `newText` property of a provided `textEdit`.
|
||||||
lsInsertTextFormat insertTextFormat = lsInsertTextFormat::Snippet;
|
lsInsertTextFormat insertTextFormat = lsInsertTextFormat::Snippet;
|
||||||
|
|
||||||
// An edit which is applied to a document when selecting this completion. When an edit is provided the value of
|
// An edit which is applied to a document when selecting this completion. When
|
||||||
// `insertText` is ignored.
|
// an edit is provided the value of `insertText` is ignored.
|
||||||
//
|
//
|
||||||
// *Note:* The range of the edit must be a single line range and it must contain the position at which completion
|
// *Note:* The range of the edit must be a single line range and it must
|
||||||
// has been requested.
|
// contain the position at which completion has been requested.
|
||||||
optional<lsTextEdit> textEdit;
|
optional<lsTextEdit> textEdit;
|
||||||
|
|
||||||
// An optional array of additional text edits that are applied when
|
// An optional array of additional text edits that are applied when
|
||||||
@ -453,10 +454,9 @@ struct lsCompletionItem {
|
|||||||
// nor with themselves.
|
// nor with themselves.
|
||||||
// std::vector<TextEdit> additionalTextEdits;
|
// std::vector<TextEdit> additionalTextEdits;
|
||||||
|
|
||||||
// An optional command that is executed *after* inserting this completion. *Note* that
|
// An optional command that is executed *after* inserting this completion.
|
||||||
// additional modifications to the current document should be described with the
|
// *Note* that additional modifications to the current document should be
|
||||||
// additionalTextEdits-property.
|
// described with the additionalTextEdits-property. Command command;
|
||||||
// Command command;
|
|
||||||
|
|
||||||
// An data entry field that is preserved on a completion item between
|
// An data entry field that is preserved on a completion item between
|
||||||
// a completion and a completion resolve request.
|
// a completion and a completion resolve request.
|
||||||
@ -468,14 +468,14 @@ struct lsCompletionItem {
|
|||||||
const std::string& InsertedContent() const;
|
const std::string& InsertedContent() const;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsCompletionItem,
|
MAKE_REFLECT_STRUCT(lsCompletionItem,
|
||||||
label,
|
label,
|
||||||
kind,
|
kind,
|
||||||
detail,
|
detail,
|
||||||
documentation,
|
documentation,
|
||||||
sortText,
|
sortText,
|
||||||
insertText,
|
insertText,
|
||||||
insertTextFormat,
|
insertTextFormat,
|
||||||
textEdit);
|
textEdit);
|
||||||
|
|
||||||
struct lsTextDocumentItem {
|
struct lsTextDocumentItem {
|
||||||
// The text document's URI.
|
// The text document's URI.
|
||||||
@ -505,7 +505,7 @@ MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits);
|
|||||||
struct lsWorkspaceEdit {
|
struct lsWorkspaceEdit {
|
||||||
// Holds changes to existing resources.
|
// Holds changes to existing resources.
|
||||||
// changes ? : { [uri:string]: TextEdit[]; };
|
// changes ? : { [uri:string]: TextEdit[]; };
|
||||||
//std::unordered_map<lsDocumentUri, std::vector<lsTextEdit>> changes;
|
// std::unordered_map<lsDocumentUri, std::vector<lsTextEdit>> changes;
|
||||||
|
|
||||||
// An array of `TextDocumentEdit`s to express changes to specific a specific
|
// An array of `TextDocumentEdit`s to express changes to specific a specific
|
||||||
// version of a text document. Whether a client supports versioned document
|
// version of a text document. Whether a client supports versioned document
|
||||||
@ -529,10 +529,10 @@ MAKE_REFLECT_TYPE_PROXY(lsDocumentHighlightKind, int);
|
|||||||
// special attention. Usually a document highlight is visualized by changing
|
// special attention. Usually a document highlight is visualized by changing
|
||||||
// the background color of its range.
|
// the background color of its range.
|
||||||
struct lsDocumentHighlight {
|
struct lsDocumentHighlight {
|
||||||
// The range this highlight applies to.
|
// The range this highlight applies to.
|
||||||
lsRange range;
|
lsRange range;
|
||||||
|
|
||||||
// The highlight kind, default is DocumentHighlightKind.Text.
|
// The highlight kind, default is DocumentHighlightKind.Text.
|
||||||
lsDocumentHighlightKind kind = lsDocumentHighlightKind::Text;
|
lsDocumentHighlightKind kind = lsDocumentHighlightKind::Text;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind);
|
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind);
|
||||||
@ -572,7 +572,6 @@ struct lsDiagnostic {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message);
|
MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message);
|
||||||
|
|
||||||
|
|
||||||
// TODO: DocumentFilter
|
// TODO: DocumentFilter
|
||||||
// TODO: DocumentSelector
|
// TODO: DocumentSelector
|
||||||
|
|
||||||
@ -687,17 +686,17 @@ struct lsWorkspaceClientCapabilites {
|
|||||||
// Capabilities specific to `WorkspaceEdit`s
|
// Capabilities specific to `WorkspaceEdit`s
|
||||||
optional<lsWorkspaceEdit> workspaceEdit;
|
optional<lsWorkspaceEdit> workspaceEdit;
|
||||||
|
|
||||||
|
|
||||||
struct lsGenericDynamicReg {
|
struct lsGenericDynamicReg {
|
||||||
// Did foo notification supports dynamic registration.
|
// Did foo notification supports dynamic registration.
|
||||||
optional<bool> dynamicRegistration;
|
optional<bool> dynamicRegistration;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Capabilities specific to the `workspace/didChangeConfiguration`
|
||||||
// Capabilities specific to the `workspace/didChangeConfiguration` notification.
|
// notification.
|
||||||
optional<lsGenericDynamicReg> didChangeConfiguration;
|
optional<lsGenericDynamicReg> didChangeConfiguration;
|
||||||
|
|
||||||
// Capabilities specific to the `workspace/didChangeWatchedFiles` notification.
|
// Capabilities specific to the `workspace/didChangeWatchedFiles`
|
||||||
|
// notification.
|
||||||
optional<lsGenericDynamicReg> didChangeWatchedFiles;
|
optional<lsGenericDynamicReg> didChangeWatchedFiles;
|
||||||
|
|
||||||
// Capabilities specific to the `workspace/symbol` request.
|
// Capabilities specific to the `workspace/symbol` request.
|
||||||
@ -707,17 +706,17 @@ struct lsWorkspaceClientCapabilites {
|
|||||||
optional<lsGenericDynamicReg> executeCommand;
|
optional<lsGenericDynamicReg> executeCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsWorkspaceEdit, documentChanges);
|
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsWorkspaceEdit,
|
||||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsGenericDynamicReg, dynamicRegistration);
|
documentChanges);
|
||||||
|
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites::lsGenericDynamicReg,
|
||||||
|
dynamicRegistration);
|
||||||
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites,
|
MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites,
|
||||||
applyEdit,
|
applyEdit,
|
||||||
workspaceEdit,
|
workspaceEdit,
|
||||||
didChangeConfiguration,
|
didChangeConfiguration,
|
||||||
didChangeWatchedFiles,
|
didChangeWatchedFiles,
|
||||||
symbol,
|
symbol,
|
||||||
executeCommand);
|
executeCommand);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Text document specific client capabilities.
|
// Text document specific client capabilities.
|
||||||
struct lsTextDocumentClientCapabilities {
|
struct lsTextDocumentClientCapabilities {
|
||||||
@ -810,27 +809,39 @@ struct lsTextDocumentClientCapabilities {
|
|||||||
optional<lsGenericDynamicReg> rename;
|
optional<lsGenericDynamicReg> rename;
|
||||||
};
|
};
|
||||||
|
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsSynchronization, dynamicRegistration, willSave, willSaveWaitUntil, didSave);
|
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsSynchronization,
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion, dynamicRegistration, completionItem);
|
dynamicRegistration,
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem, snippetSupport);
|
willSave,
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsGenericDynamicReg, dynamicRegistration);
|
willSaveWaitUntil,
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::CodeLensRegistrationOptions, dynamicRegistration, resolveProvider);
|
didSave);
|
||||||
|
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsCompletion,
|
||||||
|
dynamicRegistration,
|
||||||
|
completionItem);
|
||||||
|
MAKE_REFLECT_STRUCT(
|
||||||
|
lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem,
|
||||||
|
snippetSupport);
|
||||||
|
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities::lsGenericDynamicReg,
|
||||||
|
dynamicRegistration);
|
||||||
|
MAKE_REFLECT_STRUCT(
|
||||||
|
lsTextDocumentClientCapabilities::CodeLensRegistrationOptions,
|
||||||
|
dynamicRegistration,
|
||||||
|
resolveProvider);
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
|
MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities,
|
||||||
synchronization,
|
synchronization,
|
||||||
completion,
|
completion,
|
||||||
hover,
|
hover,
|
||||||
signatureHelp,
|
signatureHelp,
|
||||||
references,
|
references,
|
||||||
documentHighlight,
|
documentHighlight,
|
||||||
documentSymbol,
|
documentSymbol,
|
||||||
formatting,
|
formatting,
|
||||||
rangeFormatting,
|
rangeFormatting,
|
||||||
onTypeFormatting,
|
onTypeFormatting,
|
||||||
definition,
|
definition,
|
||||||
codeAction,
|
codeAction,
|
||||||
codeLens,
|
codeLens,
|
||||||
documentLink,
|
documentLink,
|
||||||
rename);
|
rename);
|
||||||
|
|
||||||
struct lsClientCapabilities {
|
struct lsClientCapabilities {
|
||||||
// Workspace specific client capabilities.
|
// Workspace specific client capabilities.
|
||||||
@ -840,8 +851,8 @@ struct lsClientCapabilities {
|
|||||||
optional<lsTextDocumentClientCapabilities> textDocument;
|
optional<lsTextDocumentClientCapabilities> textDocument;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Experimental client capabilities.
|
* Experimental client capabilities.
|
||||||
*/
|
*/
|
||||||
// experimental?: any; // TODO
|
// experimental?: any; // TODO
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument);
|
MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument);
|
||||||
@ -849,7 +860,8 @@ MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument);
|
|||||||
struct lsInitializeParams {
|
struct lsInitializeParams {
|
||||||
// The process Id of the parent process that started
|
// The process Id of the parent process that started
|
||||||
// the server. Is null if the process has not been started by another process.
|
// the server. Is null if the process has not been started by another process.
|
||||||
// If the parent process is not alive then the server should exit (see exit notification) its process.
|
// If the parent process is not alive then the server should exit (see exit
|
||||||
|
// notification) its process.
|
||||||
optional<int> processId;
|
optional<int> processId;
|
||||||
|
|
||||||
// The rootPath of the workspace. Is null
|
// The rootPath of the workspace. Is null
|
||||||
@ -871,9 +883,9 @@ struct lsInitializeParams {
|
|||||||
|
|
||||||
enum class lsTrace {
|
enum class lsTrace {
|
||||||
// NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose';
|
// NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose';
|
||||||
Off, // off
|
Off, // off
|
||||||
Messages, // messages
|
Messages, // messages
|
||||||
Verbose // verbose
|
Verbose // verbose
|
||||||
};
|
};
|
||||||
|
|
||||||
// The initial trace setting. If omitted trace is disabled ('off').
|
// The initial trace setting. If omitted trace is disabled ('off').
|
||||||
@ -881,8 +893,13 @@ struct lsInitializeParams {
|
|||||||
};
|
};
|
||||||
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value);
|
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value);
|
||||||
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value);
|
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value);
|
||||||
MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri, initializationOptions, capabilities, trace);
|
MAKE_REFLECT_STRUCT(lsInitializeParams,
|
||||||
|
processId,
|
||||||
|
rootPath,
|
||||||
|
rootUri,
|
||||||
|
initializationOptions,
|
||||||
|
capabilities,
|
||||||
|
trace);
|
||||||
|
|
||||||
struct lsInitializeError {
|
struct lsInitializeError {
|
||||||
// Indicates whether the client should retry to send the
|
// Indicates whether the client should retry to send the
|
||||||
@ -892,7 +909,8 @@ struct lsInitializeError {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsInitializeError, retry);
|
MAKE_REFLECT_STRUCT(lsInitializeError, retry);
|
||||||
|
|
||||||
// Defines how the host (editor) should sync document changes to the language server.
|
// Defines how the host (editor) should sync document changes to the language
|
||||||
|
// server.
|
||||||
enum class lsTextDocumentSyncKind {
|
enum class lsTextDocumentSyncKind {
|
||||||
// Documents should not be synced at all.
|
// Documents should not be synced at all.
|
||||||
None = 0,
|
None = 0,
|
||||||
@ -941,7 +959,9 @@ struct lsDocumentOnTypeFormattingOptions {
|
|||||||
// More trigger characters.
|
// More trigger characters.
|
||||||
NonElidedVector<std::string> moreTriggerCharacter;
|
NonElidedVector<std::string> moreTriggerCharacter;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, firstTriggerCharacter, moreTriggerCharacter);
|
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions,
|
||||||
|
firstTriggerCharacter,
|
||||||
|
moreTriggerCharacter);
|
||||||
|
|
||||||
// Document link options
|
// Document link options
|
||||||
struct lsDocumentLinkOptions {
|
struct lsDocumentLinkOptions {
|
||||||
@ -967,8 +987,8 @@ MAKE_REFLECT_STRUCT(lsSaveOptions, includeText);
|
|||||||
struct lsTextDocumentSyncOptions {
|
struct lsTextDocumentSyncOptions {
|
||||||
// Open and close notifications are sent to the server.
|
// Open and close notifications are sent to the server.
|
||||||
bool openClose = false;
|
bool openClose = false;
|
||||||
// Change notificatins are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full
|
// Change notificatins are sent to the server. See TextDocumentSyncKind.None,
|
||||||
// and TextDocumentSyncKindIncremental.
|
// TextDocumentSyncKind.Full and TextDocumentSyncKindIncremental.
|
||||||
lsTextDocumentSyncKind change = lsTextDocumentSyncKind::Incremental;
|
lsTextDocumentSyncKind change = lsTextDocumentSyncKind::Incremental;
|
||||||
// Will save notifications are sent to the server.
|
// Will save notifications are sent to the server.
|
||||||
optional<bool> willSave;
|
optional<bool> willSave;
|
||||||
@ -977,11 +997,17 @@ struct lsTextDocumentSyncOptions {
|
|||||||
// Save notifications are sent to the server.
|
// Save notifications are sent to the server.
|
||||||
optional<lsSaveOptions> save;
|
optional<lsSaveOptions> save;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, openClose, change, willSave, willSaveWaitUntil, save);
|
MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions,
|
||||||
|
openClose,
|
||||||
|
change,
|
||||||
|
willSave,
|
||||||
|
willSaveWaitUntil,
|
||||||
|
save);
|
||||||
|
|
||||||
struct lsServerCapabilities {
|
struct lsServerCapabilities {
|
||||||
// Defines how text documents are synced. Is either a detailed structure defining each notification or
|
// Defines how text documents are synced. Is either a detailed structure
|
||||||
// for backwards compatibility the TextDocumentSyncKind number.
|
// defining each notification or for backwards compatibility the
|
||||||
|
// TextDocumentSyncKind number.
|
||||||
// TODO: It seems like the new API is broken and doesn't work.
|
// TODO: It seems like the new API is broken and doesn't work.
|
||||||
// optional<lsTextDocumentSyncOptions> textDocumentSync;
|
// optional<lsTextDocumentSyncOptions> textDocumentSync;
|
||||||
lsTextDocumentSyncKind textDocumentSync;
|
lsTextDocumentSyncKind textDocumentSync;
|
||||||
@ -1020,23 +1046,23 @@ struct lsServerCapabilities {
|
|||||||
optional<lsExecuteCommandOptions> executeCommandProvider;
|
optional<lsExecuteCommandOptions> executeCommandProvider;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsServerCapabilities,
|
MAKE_REFLECT_STRUCT(lsServerCapabilities,
|
||||||
textDocumentSync,
|
textDocumentSync,
|
||||||
hoverProvider,
|
hoverProvider,
|
||||||
completionProvider,
|
completionProvider,
|
||||||
signatureHelpProvider,
|
signatureHelpProvider,
|
||||||
definitionProvider,
|
definitionProvider,
|
||||||
referencesProvider,
|
referencesProvider,
|
||||||
documentHighlightProvider,
|
documentHighlightProvider,
|
||||||
documentSymbolProvider,
|
documentSymbolProvider,
|
||||||
workspaceSymbolProvider,
|
workspaceSymbolProvider,
|
||||||
codeActionProvider,
|
codeActionProvider,
|
||||||
codeLensProvider,
|
codeLensProvider,
|
||||||
documentFormattingProvider,
|
documentFormattingProvider,
|
||||||
documentRangeFormattingProvider,
|
documentRangeFormattingProvider,
|
||||||
documentOnTypeFormattingProvider,
|
documentOnTypeFormattingProvider,
|
||||||
renameProvider,
|
renameProvider,
|
||||||
documentLinkProvider,
|
documentLinkProvider,
|
||||||
executeCommandProvider);
|
executeCommandProvider);
|
||||||
|
|
||||||
struct Ipc_InitializeRequest : public IpcMessage<Ipc_InitializeRequest> {
|
struct Ipc_InitializeRequest : public IpcMessage<Ipc_InitializeRequest> {
|
||||||
const static IpcId kIpcId = IpcId::Initialize;
|
const static IpcId kIpcId = IpcId::Initialize;
|
||||||
@ -1056,7 +1082,8 @@ struct Out_InitializeResponse : public lsOutMessage<Out_InitializeResponse> {
|
|||||||
MAKE_REFLECT_STRUCT(Out_InitializeResponse::InitializeResult, capabilities);
|
MAKE_REFLECT_STRUCT(Out_InitializeResponse::InitializeResult, capabilities);
|
||||||
MAKE_REFLECT_STRUCT(Out_InitializeResponse, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_InitializeResponse, jsonrpc, id, result);
|
||||||
|
|
||||||
struct Ipc_InitializedNotification : public IpcMessage<Ipc_InitializedNotification> {
|
struct Ipc_InitializedNotification
|
||||||
|
: public IpcMessage<Ipc_InitializedNotification> {
|
||||||
const static IpcId kIpcId = IpcId::Initialized;
|
const static IpcId kIpcId = IpcId::Initialized;
|
||||||
|
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
@ -1136,11 +1163,6 @@ struct Out_Error : public lsOutMessage<Out_Error> {
|
|||||||
MAKE_REFLECT_STRUCT(Out_Error::lsResponseError, code, message);
|
MAKE_REFLECT_STRUCT(Out_Error::lsResponseError, code, message);
|
||||||
MAKE_REFLECT_STRUCT(Out_Error, jsonrpc, id, error);
|
MAKE_REFLECT_STRUCT(Out_Error, jsonrpc, id, error);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Cancel an existing request.
|
// Cancel an existing request.
|
||||||
struct Ipc_CancelRequest : public IpcMessage<Ipc_CancelRequest> {
|
struct Ipc_CancelRequest : public IpcMessage<Ipc_CancelRequest> {
|
||||||
static const IpcId kIpcId = IpcId::CancelRequest;
|
static const IpcId kIpcId = IpcId::CancelRequest;
|
||||||
@ -1148,10 +1170,6 @@ struct Ipc_CancelRequest : public IpcMessage<Ipc_CancelRequest> {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CancelRequest, id);
|
MAKE_REFLECT_STRUCT(Ipc_CancelRequest, id);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Open, update, close file
|
// Open, update, close file
|
||||||
struct Ipc_TextDocumentDidOpen : public IpcMessage<Ipc_TextDocumentDidOpen> {
|
struct Ipc_TextDocumentDidOpen : public IpcMessage<Ipc_TextDocumentDidOpen> {
|
||||||
struct Params {
|
struct Params {
|
||||||
@ -1163,7 +1181,8 @@ struct Ipc_TextDocumentDidOpen : public IpcMessage<Ipc_TextDocumentDidOpen> {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidOpen::Params, textDocument);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidOpen::Params, textDocument);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidOpen, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidOpen, params);
|
||||||
struct Ipc_TextDocumentDidChange : public IpcMessage<Ipc_TextDocumentDidChange> {
|
struct Ipc_TextDocumentDidChange
|
||||||
|
: public IpcMessage<Ipc_TextDocumentDidChange> {
|
||||||
struct lsTextDocumentContentChangeEvent {
|
struct lsTextDocumentContentChangeEvent {
|
||||||
// The range of the document that changed.
|
// The range of the document that changed.
|
||||||
lsRange range;
|
lsRange range;
|
||||||
@ -1181,8 +1200,13 @@ struct Ipc_TextDocumentDidChange : public IpcMessage<Ipc_TextDocumentDidChange>
|
|||||||
const static IpcId kIpcId = IpcId::TextDocumentDidChange;
|
const static IpcId kIpcId = IpcId::TextDocumentDidChange;
|
||||||
Params params;
|
Params params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent, range, rangeLength, text);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent,
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidChange::Params, textDocument, contentChanges);
|
range,
|
||||||
|
rangeLength,
|
||||||
|
text);
|
||||||
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidChange::Params,
|
||||||
|
textDocument,
|
||||||
|
contentChanges);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidChange, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidChange, params);
|
||||||
struct Ipc_TextDocumentDidClose : public IpcMessage<Ipc_TextDocumentDidClose> {
|
struct Ipc_TextDocumentDidClose : public IpcMessage<Ipc_TextDocumentDidClose> {
|
||||||
struct Params {
|
struct Params {
|
||||||
@ -1195,7 +1219,6 @@ struct Ipc_TextDocumentDidClose : public IpcMessage<Ipc_TextDocumentDidClose> {
|
|||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidClose::Params, textDocument);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidClose::Params, textDocument);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidClose, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidClose, params);
|
||||||
|
|
||||||
|
|
||||||
struct Ipc_TextDocumentDidSave : public IpcMessage<Ipc_TextDocumentDidSave> {
|
struct Ipc_TextDocumentDidSave : public IpcMessage<Ipc_TextDocumentDidSave> {
|
||||||
struct Params {
|
struct Params {
|
||||||
// The document that was saved.
|
// The document that was saved.
|
||||||
@ -1212,10 +1235,9 @@ struct Ipc_TextDocumentDidSave : public IpcMessage<Ipc_TextDocumentDidSave> {
|
|||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidSave::Params, textDocument);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidSave::Params, textDocument);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidSave, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidSave, params);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Diagnostics
|
// Diagnostics
|
||||||
struct Out_TextDocumentPublishDiagnostics : public lsOutMessage<Out_TextDocumentPublishDiagnostics> {
|
struct Out_TextDocumentPublishDiagnostics
|
||||||
|
: public lsOutMessage<Out_TextDocumentPublishDiagnostics> {
|
||||||
struct Params {
|
struct Params {
|
||||||
// The URI for which diagnostic information is reported.
|
// The URI for which diagnostic information is reported.
|
||||||
lsDocumentUri uri;
|
lsDocumentUri uri;
|
||||||
@ -1226,7 +1248,7 @@ struct Out_TextDocumentPublishDiagnostics : public lsOutMessage<Out_TextDocument
|
|||||||
|
|
||||||
Params params;
|
Params params;
|
||||||
};
|
};
|
||||||
template<typename TVisitor>
|
template <typename TVisitor>
|
||||||
void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
|
void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
|
||||||
std::string method = "textDocument/publishDiagnostics";
|
std::string method = "textDocument/publishDiagnostics";
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
@ -1235,9 +1257,9 @@ void Reflect(TVisitor& visitor, Out_TextDocumentPublishDiagnostics& value) {
|
|||||||
REFLECT_MEMBER(params);
|
REFLECT_MEMBER(params);
|
||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, uri, diagnostics);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params,
|
||||||
|
uri,
|
||||||
|
diagnostics);
|
||||||
|
|
||||||
// Rename
|
// Rename
|
||||||
struct Ipc_TextDocumentRename : public IpcMessage<Ipc_TextDocumentRename> {
|
struct Ipc_TextDocumentRename : public IpcMessage<Ipc_TextDocumentRename> {
|
||||||
@ -1258,7 +1280,10 @@ struct Ipc_TextDocumentRename : public IpcMessage<Ipc_TextDocumentRename> {
|
|||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
Params params;
|
Params params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentRename::Params, textDocument, position, newName);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentRename::Params,
|
||||||
|
textDocument,
|
||||||
|
position,
|
||||||
|
newName);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentRename, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentRename, id, params);
|
||||||
struct Out_TextDocumentRename : public lsOutMessage<Out_TextDocumentRename> {
|
struct Out_TextDocumentRename : public lsOutMessage<Out_TextDocumentRename> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
@ -1266,10 +1291,6 @@ struct Out_TextDocumentRename : public lsOutMessage<Out_TextDocumentRename> {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Code completion
|
// Code completion
|
||||||
struct Ipc_TextDocumentComplete : public IpcMessage<Ipc_TextDocumentComplete> {
|
struct Ipc_TextDocumentComplete : public IpcMessage<Ipc_TextDocumentComplete> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentCompletion;
|
const static IpcId kIpcId = IpcId::TextDocumentCompletion;
|
||||||
@ -1286,14 +1307,16 @@ struct lsTextDocumentCompleteResult {
|
|||||||
NonElidedVector<lsCompletionItem> items;
|
NonElidedVector<lsCompletionItem> items;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentCompleteResult, isIncomplete, items);
|
MAKE_REFLECT_STRUCT(lsTextDocumentCompleteResult, isIncomplete, items);
|
||||||
struct Out_TextDocumentComplete : public lsOutMessage<Out_TextDocumentComplete> {
|
struct Out_TextDocumentComplete
|
||||||
|
: public lsOutMessage<Out_TextDocumentComplete> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsTextDocumentCompleteResult result;
|
lsTextDocumentCompleteResult result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result);
|
||||||
|
|
||||||
// Signature help.
|
// Signature help.
|
||||||
struct Ipc_TextDocumentSignatureHelp : public IpcMessage<Ipc_TextDocumentSignatureHelp> {
|
struct Ipc_TextDocumentSignatureHelp
|
||||||
|
: public IpcMessage<Ipc_TextDocumentSignatureHelp> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentSignatureHelp;
|
const static IpcId kIpcId = IpcId::TextDocumentSignatureHelp;
|
||||||
|
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
@ -1353,36 +1376,44 @@ struct lsSignatureHelp {
|
|||||||
// active signature does have any.
|
// active signature does have any.
|
||||||
optional<int> activeParameter;
|
optional<int> activeParameter;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature, activeParameter);
|
MAKE_REFLECT_STRUCT(lsSignatureHelp,
|
||||||
struct Out_TextDocumentSignatureHelp : public lsOutMessage<Out_TextDocumentSignatureHelp> {
|
signatures,
|
||||||
|
activeSignature,
|
||||||
|
activeParameter);
|
||||||
|
struct Out_TextDocumentSignatureHelp
|
||||||
|
: public lsOutMessage<Out_TextDocumentSignatureHelp> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsSignatureHelp result;
|
lsSignatureHelp result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentSignatureHelp, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentSignatureHelp, jsonrpc, id, result);
|
||||||
|
|
||||||
// Goto definition
|
// Goto definition
|
||||||
struct Ipc_TextDocumentDefinition : public IpcMessage<Ipc_TextDocumentDefinition> {
|
struct Ipc_TextDocumentDefinition
|
||||||
|
: public IpcMessage<Ipc_TextDocumentDefinition> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentDefinition;
|
const static IpcId kIpcId = IpcId::TextDocumentDefinition;
|
||||||
|
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsTextDocumentPositionParams params;
|
lsTextDocumentPositionParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDefinition, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDefinition, id, params);
|
||||||
struct Out_TextDocumentDefinition : public lsOutMessage<Out_TextDocumentDefinition> {
|
struct Out_TextDocumentDefinition
|
||||||
|
: public lsOutMessage<Out_TextDocumentDefinition> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<lsLocation> result;
|
NonElidedVector<lsLocation> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentDefinition, jsonrpc, id, result);
|
||||||
|
|
||||||
// Document highlight
|
// Document highlight
|
||||||
struct Ipc_TextDocumentDocumentHighlight : public IpcMessage<Ipc_TextDocumentDocumentHighlight> {
|
struct Ipc_TextDocumentDocumentHighlight
|
||||||
|
: public IpcMessage<Ipc_TextDocumentDocumentHighlight> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentDocumentHighlight;
|
const static IpcId kIpcId = IpcId::TextDocumentDocumentHighlight;
|
||||||
|
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsTextDocumentPositionParams params;
|
lsTextDocumentPositionParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentHighlight, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentHighlight, id, params);
|
||||||
struct Out_TextDocumentDocumentHighlight : public lsOutMessage<Out_TextDocumentDocumentHighlight> {
|
struct Out_TextDocumentDocumentHighlight
|
||||||
|
: public lsOutMessage<Out_TextDocumentDocumentHighlight> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<lsDocumentHighlight> result;
|
NonElidedVector<lsDocumentHighlight> result;
|
||||||
};
|
};
|
||||||
@ -1409,7 +1440,8 @@ MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range);
|
|||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentHover, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentHover, jsonrpc, id, result);
|
||||||
|
|
||||||
// References
|
// References
|
||||||
struct Ipc_TextDocumentReferences : public IpcMessage<Ipc_TextDocumentReferences> {
|
struct Ipc_TextDocumentReferences
|
||||||
|
: public IpcMessage<Ipc_TextDocumentReferences> {
|
||||||
struct lsReferenceContext {
|
struct lsReferenceContext {
|
||||||
// Include the declaration of the current symbol.
|
// Include the declaration of the current symbol.
|
||||||
bool includeDeclaration;
|
bool includeDeclaration;
|
||||||
@ -1425,41 +1457,52 @@ struct Ipc_TextDocumentReferences : public IpcMessage<Ipc_TextDocumentReferences
|
|||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsReferenceParams params;
|
lsReferenceParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentReferences::lsReferenceContext, includeDeclaration);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentReferences::lsReferenceContext,
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentReferences::lsReferenceParams, textDocument, position, context);
|
includeDeclaration);
|
||||||
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentReferences::lsReferenceParams,
|
||||||
|
textDocument,
|
||||||
|
position,
|
||||||
|
context);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentReferences, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentReferences, id, params);
|
||||||
struct Out_TextDocumentReferences : public lsOutMessage<Out_TextDocumentReferences> {
|
struct Out_TextDocumentReferences
|
||||||
|
: public lsOutMessage<Out_TextDocumentReferences> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<lsLocation> result;
|
NonElidedVector<lsLocation> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentReferences, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentReferences, jsonrpc, id, result);
|
||||||
|
|
||||||
// Code action
|
// Code action
|
||||||
struct Ipc_TextDocumentCodeAction : public IpcMessage<Ipc_TextDocumentCodeAction> {
|
struct Ipc_TextDocumentCodeAction
|
||||||
|
: public IpcMessage<Ipc_TextDocumentCodeAction> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentCodeAction;
|
const static IpcId kIpcId = IpcId::TextDocumentCodeAction;
|
||||||
// Contains additional diagnostic information about the context in which
|
// Contains additional diagnostic information about the context in which
|
||||||
// a code action is run.
|
// a code action is run.
|
||||||
struct lsCodeActionContext {
|
struct lsCodeActionContext {
|
||||||
// An array of diagnostics.
|
// An array of diagnostics.
|
||||||
NonElidedVector<lsDiagnostic> diagnostics;
|
NonElidedVector<lsDiagnostic> diagnostics;
|
||||||
};
|
};
|
||||||
// Params for the CodeActionRequest
|
// Params for the CodeActionRequest
|
||||||
struct lsCodeActionParams {
|
struct lsCodeActionParams {
|
||||||
// The document in which the command was invoked.
|
// The document in which the command was invoked.
|
||||||
lsTextDocumentIdentifier textDocument;
|
lsTextDocumentIdentifier textDocument;
|
||||||
// The range for which the command was invoked.
|
// The range for which the command was invoked.
|
||||||
lsRange range;
|
lsRange range;
|
||||||
// Context carrying additional information.
|
// Context carrying additional information.
|
||||||
lsCodeActionContext context;
|
lsCodeActionContext context;
|
||||||
};
|
};
|
||||||
|
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsCodeActionParams params;
|
lsCodeActionParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeAction::lsCodeActionContext, diagnostics);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeAction::lsCodeActionContext,
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeAction::lsCodeActionParams, textDocument, range, context);
|
diagnostics);
|
||||||
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeAction::lsCodeActionParams,
|
||||||
|
textDocument,
|
||||||
|
range,
|
||||||
|
context);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeAction, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeAction, id, params);
|
||||||
struct Out_TextDocumentCodeAction : public lsOutMessage<Out_TextDocumentCodeAction> {
|
struct Out_TextDocumentCodeAction
|
||||||
|
: public lsOutMessage<Out_TextDocumentCodeAction> {
|
||||||
struct CommandArgs {
|
struct CommandArgs {
|
||||||
lsDocumentUri textDocumentUri;
|
lsDocumentUri textDocumentUri;
|
||||||
NonElidedVector<lsTextEdit> edits;
|
NonElidedVector<lsTextEdit> edits;
|
||||||
@ -1469,7 +1512,9 @@ struct Out_TextDocumentCodeAction : public lsOutMessage<Out_TextDocumentCodeActi
|
|||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<Command> result;
|
NonElidedVector<Command> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(Out_TextDocumentCodeAction::CommandArgs, textDocumentUri, edits);
|
MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(Out_TextDocumentCodeAction::CommandArgs,
|
||||||
|
textDocumentUri,
|
||||||
|
edits);
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result);
|
||||||
|
|
||||||
// List symbols in a document.
|
// List symbols in a document.
|
||||||
@ -1477,21 +1522,24 @@ struct lsDocumentSymbolParams {
|
|||||||
lsTextDocumentIdentifier textDocument;
|
lsTextDocumentIdentifier textDocument;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDocumentSymbolParams, textDocument);
|
MAKE_REFLECT_STRUCT(lsDocumentSymbolParams, textDocument);
|
||||||
struct Ipc_TextDocumentDocumentSymbol : public IpcMessage<Ipc_TextDocumentDocumentSymbol> {
|
struct Ipc_TextDocumentDocumentSymbol
|
||||||
|
: public IpcMessage<Ipc_TextDocumentDocumentSymbol> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentDocumentSymbol;
|
const static IpcId kIpcId = IpcId::TextDocumentDocumentSymbol;
|
||||||
|
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsDocumentSymbolParams params;
|
lsDocumentSymbolParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentSymbol, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentSymbol, id, params);
|
||||||
struct Out_TextDocumentDocumentSymbol : public lsOutMessage<Out_TextDocumentDocumentSymbol> {
|
struct Out_TextDocumentDocumentSymbol
|
||||||
|
: public lsOutMessage<Out_TextDocumentDocumentSymbol> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<lsSymbolInformation> result;
|
NonElidedVector<lsSymbolInformation> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
|
||||||
|
|
||||||
// List links a document
|
// List links a document
|
||||||
struct Ipc_TextDocumentDocumentLink : public IpcMessage<Ipc_TextDocumentDocumentLink> {
|
struct Ipc_TextDocumentDocumentLink
|
||||||
|
: public IpcMessage<Ipc_TextDocumentDocumentLink> {
|
||||||
const static IpcId kIpcId = IpcId::TextDocumentDocumentLink;
|
const static IpcId kIpcId = IpcId::TextDocumentDocumentLink;
|
||||||
|
|
||||||
struct DocumentLinkParams {
|
struct DocumentLinkParams {
|
||||||
@ -1502,24 +1550,25 @@ struct Ipc_TextDocumentDocumentLink : public IpcMessage<Ipc_TextDocumentDocument
|
|||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
DocumentLinkParams params;
|
DocumentLinkParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink::DocumentLinkParams, textDocument);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink::DocumentLinkParams,
|
||||||
|
textDocument);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink, id, params);
|
||||||
// A document link is a range in a text document that links to an internal or external resource, like another
|
// A document link is a range in a text document that links to an internal or
|
||||||
// text document or a web site.
|
// external resource, like another text document or a web site.
|
||||||
struct lsDocumentLink {
|
struct lsDocumentLink {
|
||||||
// The range this link applies to.
|
// The range this link applies to.
|
||||||
lsRange range;
|
lsRange range;
|
||||||
// The uri this link points to. If missing a resolve request is sent later.
|
// The uri this link points to. If missing a resolve request is sent later.
|
||||||
optional<lsDocumentUri> target;
|
optional<lsDocumentUri> target;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDocumentLink, range, target);
|
MAKE_REFLECT_STRUCT(lsDocumentLink, range, target);
|
||||||
struct Out_TextDocumentDocumentLink : public lsOutMessage<Out_TextDocumentDocumentLink> {
|
struct Out_TextDocumentDocumentLink
|
||||||
|
: public lsOutMessage<Out_TextDocumentDocumentLink> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<lsDocumentLink> result;
|
NonElidedVector<lsDocumentLink> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentLink, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentLink, jsonrpc, id, result);
|
||||||
|
|
||||||
|
|
||||||
// List code lens in a document.
|
// List code lens in a document.
|
||||||
struct lsDocumentCodeLensParams {
|
struct lsDocumentCodeLensParams {
|
||||||
lsTextDocumentIdentifier textDocument;
|
lsTextDocumentIdentifier textDocument;
|
||||||
@ -1541,9 +1590,11 @@ struct Ipc_TextDocumentCodeLens : public IpcMessage<Ipc_TextDocumentCodeLens> {
|
|||||||
lsDocumentCodeLensParams params;
|
lsDocumentCodeLensParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeLens, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentCodeLens, id, params);
|
||||||
struct Out_TextDocumentCodeLens : public lsOutMessage<Out_TextDocumentCodeLens> {
|
struct Out_TextDocumentCodeLens
|
||||||
|
: public lsOutMessage<Out_TextDocumentCodeLens> {
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
NonElidedVector<lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>> result;
|
NonElidedVector<lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>>
|
||||||
|
result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
|
||||||
struct Ipc_CodeLensResolve : public IpcMessage<Ipc_CodeLensResolve> {
|
struct Ipc_CodeLensResolve : public IpcMessage<Ipc_CodeLensResolve> {
|
||||||
@ -1577,12 +1628,7 @@ struct Out_WorkspaceSymbol : public lsOutMessage<Out_WorkspaceSymbol> {
|
|||||||
MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result);
|
||||||
|
|
||||||
// Show a message to the user.
|
// Show a message to the user.
|
||||||
enum class lsMessageType : int {
|
enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 };
|
||||||
Error = 1,
|
|
||||||
Warning = 2,
|
|
||||||
Info = 3,
|
|
||||||
Log = 4
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_TYPE_PROXY(lsMessageType, int)
|
MAKE_REFLECT_TYPE_PROXY(lsMessageType, int)
|
||||||
struct Out_ShowLogMessageParams {
|
struct Out_ShowLogMessageParams {
|
||||||
lsMessageType type = lsMessageType::Error;
|
lsMessageType type = lsMessageType::Error;
|
||||||
@ -1590,15 +1636,13 @@ struct Out_ShowLogMessageParams {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, type, message);
|
MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, type, message);
|
||||||
struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
|
struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
|
||||||
enum class DisplayType {
|
enum class DisplayType { Show, Log };
|
||||||
Show, Log
|
|
||||||
};
|
|
||||||
DisplayType display_type = DisplayType::Show;
|
DisplayType display_type = DisplayType::Show;
|
||||||
|
|
||||||
std::string method();
|
std::string method();
|
||||||
Out_ShowLogMessageParams params;
|
Out_ShowLogMessageParams params;
|
||||||
};
|
};
|
||||||
template<typename TVisitor>
|
template <typename TVisitor>
|
||||||
void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
|
void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER(jsonrpc);
|
REFLECT_MEMBER(jsonrpc);
|
||||||
@ -1608,8 +1652,8 @@ void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Out_CquerySetInactiveRegion
|
||||||
struct Out_CquerySetInactiveRegion : public lsOutMessage<Out_CquerySetInactiveRegion> {
|
: public lsOutMessage<Out_CquerySetInactiveRegion> {
|
||||||
struct Params {
|
struct Params {
|
||||||
lsDocumentUri uri;
|
lsDocumentUri uri;
|
||||||
NonElidedVector<lsRange> inactiveRegions;
|
NonElidedVector<lsRange> inactiveRegions;
|
||||||
@ -1620,7 +1664,6 @@ struct Out_CquerySetInactiveRegion : public lsOutMessage<Out_CquerySetInactiveRe
|
|||||||
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion::Params, uri, inactiveRegions);
|
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion::Params, uri, inactiveRegions);
|
||||||
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion, jsonrpc, method, params);
|
MAKE_REFLECT_STRUCT(Out_CquerySetInactiveRegion, jsonrpc, method, params);
|
||||||
|
|
||||||
|
|
||||||
struct Ipc_CqueryFreshenIndex : public IpcMessage<Ipc_CqueryFreshenIndex> {
|
struct Ipc_CqueryFreshenIndex : public IpcMessage<Ipc_CqueryFreshenIndex> {
|
||||||
const static IpcId kIpcId = IpcId::CqueryFreshenIndex;
|
const static IpcId kIpcId = IpcId::CqueryFreshenIndex;
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
@ -1628,13 +1671,15 @@ struct Ipc_CqueryFreshenIndex : public IpcMessage<Ipc_CqueryFreshenIndex> {
|
|||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryFreshenIndex, id);
|
MAKE_REFLECT_STRUCT(Ipc_CqueryFreshenIndex, id);
|
||||||
|
|
||||||
// Type Hierarchy Tree
|
// Type Hierarchy Tree
|
||||||
struct Ipc_CqueryTypeHierarchyTree : public IpcMessage<Ipc_CqueryTypeHierarchyTree> {
|
struct Ipc_CqueryTypeHierarchyTree
|
||||||
|
: public IpcMessage<Ipc_CqueryTypeHierarchyTree> {
|
||||||
const static IpcId kIpcId = IpcId::CqueryTypeHierarchyTree;
|
const static IpcId kIpcId = IpcId::CqueryTypeHierarchyTree;
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsTextDocumentPositionParams params;
|
lsTextDocumentPositionParams params;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryTypeHierarchyTree, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_CqueryTypeHierarchyTree, id, params);
|
||||||
struct Out_CqueryTypeHierarchyTree : public lsOutMessage<Out_CqueryTypeHierarchyTree> {
|
struct Out_CqueryTypeHierarchyTree
|
||||||
|
: public lsOutMessage<Out_CqueryTypeHierarchyTree> {
|
||||||
struct TypeEntry {
|
struct TypeEntry {
|
||||||
std::string name;
|
std::string name;
|
||||||
optional<lsLocation> location;
|
optional<lsLocation> location;
|
||||||
@ -1643,11 +1688,15 @@ struct Out_CqueryTypeHierarchyTree : public lsOutMessage<Out_CqueryTypeHierarchy
|
|||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
optional<TypeEntry> result;
|
optional<TypeEntry> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryTypeHierarchyTree::TypeEntry, name, location, children);
|
MAKE_REFLECT_STRUCT(Out_CqueryTypeHierarchyTree::TypeEntry,
|
||||||
|
name,
|
||||||
|
location,
|
||||||
|
children);
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryTypeHierarchyTree, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_CqueryTypeHierarchyTree, jsonrpc, id, result);
|
||||||
|
|
||||||
// Call Tree
|
// Call Tree
|
||||||
struct Ipc_CqueryCallTreeInitial : public IpcMessage<Ipc_CqueryCallTreeInitial> {
|
struct Ipc_CqueryCallTreeInitial
|
||||||
|
: public IpcMessage<Ipc_CqueryCallTreeInitial> {
|
||||||
const static IpcId kIpcId = IpcId::CqueryCallTreeInitial;
|
const static IpcId kIpcId = IpcId::CqueryCallTreeInitial;
|
||||||
lsRequestId id;
|
lsRequestId id;
|
||||||
lsTextDocumentPositionParams params;
|
lsTextDocumentPositionParams params;
|
||||||
@ -1664,9 +1713,7 @@ struct Ipc_CqueryCallTreeExpand : public IpcMessage<Ipc_CqueryCallTreeExpand> {
|
|||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand::Params, usr);
|
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand::Params, usr);
|
||||||
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand, id, params);
|
MAKE_REFLECT_STRUCT(Ipc_CqueryCallTreeExpand, id, params);
|
||||||
struct Out_CqueryCallTree : public lsOutMessage<Out_CqueryCallTree> {
|
struct Out_CqueryCallTree : public lsOutMessage<Out_CqueryCallTree> {
|
||||||
enum class CallType {
|
enum class CallType { Direct = 0, Base = 1, Derived = 2 };
|
||||||
Direct = 0, Base = 1, Derived = 2
|
|
||||||
};
|
|
||||||
struct CallEntry {
|
struct CallEntry {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string usr;
|
std::string usr;
|
||||||
@ -1679,7 +1726,12 @@ struct Out_CqueryCallTree : public lsOutMessage<Out_CqueryCallTree> {
|
|||||||
NonElidedVector<CallEntry> result;
|
NonElidedVector<CallEntry> result;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_TYPE_PROXY(Out_CqueryCallTree::CallType, int);
|
MAKE_REFLECT_TYPE_PROXY(Out_CqueryCallTree::CallType, int);
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryCallTree::CallEntry, name, usr, location, hasCallers, callType);
|
MAKE_REFLECT_STRUCT(Out_CqueryCallTree::CallEntry,
|
||||||
|
name,
|
||||||
|
usr,
|
||||||
|
location,
|
||||||
|
hasCallers,
|
||||||
|
callType);
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryCallTree, jsonrpc, id, result);
|
MAKE_REFLECT_STRUCT(Out_CqueryCallTree, jsonrpc, id, result);
|
||||||
|
|
||||||
// Vars, Callers, Derived, GotoParent
|
// Vars, Callers, Derived, GotoParent
|
||||||
|
@ -20,7 +20,9 @@ int GetOffsetForPosition(lsPosition position, const std::string& content) {
|
|||||||
return std::min<int>(offset + position.character, content.size());
|
return std::min<int>(offset + position.character, content.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
lsPosition CharPos(const std::string& search, char character, int character_offset) {
|
lsPosition CharPos(const std::string& search,
|
||||||
|
char character,
|
||||||
|
int character_offset) {
|
||||||
lsPosition result;
|
lsPosition result;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (index < search.size()) {
|
while (index < search.size()) {
|
||||||
@ -30,8 +32,7 @@ lsPosition CharPos(const std::string& search, char character, int character_offs
|
|||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
result.line += 1;
|
result.line += 1;
|
||||||
result.character = 0;
|
result.character = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
result.character += 1;
|
result.character += 1;
|
||||||
}
|
}
|
||||||
++index;
|
++index;
|
||||||
@ -75,7 +76,11 @@ optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line) {
|
|||||||
return lsRange(lsPosition(line_number, start), lsPosition(line_number, end));
|
return lsRange(lsPosition(line_number, start), lsPosition(line_number, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LexFunctionDeclaration(const std::string& buffer_content, lsPosition declaration_spelling, optional<std::string> type_name, std::string* insert_text, int* newlines_after_name) {
|
void LexFunctionDeclaration(const std::string& buffer_content,
|
||||||
|
lsPosition declaration_spelling,
|
||||||
|
optional<std::string> type_name,
|
||||||
|
std::string* insert_text,
|
||||||
|
int* newlines_after_name) {
|
||||||
int name_start = GetOffsetForPosition(declaration_spelling, buffer_content);
|
int name_start = GetOffsetForPosition(declaration_spelling, buffer_content);
|
||||||
|
|
||||||
bool parse_return_type = true;
|
bool parse_return_type = true;
|
||||||
@ -89,7 +94,8 @@ void LexFunctionDeclaration(const std::string& buffer_content, lsPosition declar
|
|||||||
++name_end;
|
++name_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string func_name = buffer_content.substr(name_start, name_end - name_start);
|
std::string func_name =
|
||||||
|
buffer_content.substr(name_start, name_end - name_start);
|
||||||
if (func_name == *type_name || func_name == ("~" + *type_name))
|
if (func_name == *type_name || func_name == ("~" + *type_name))
|
||||||
parse_return_type = false;
|
parse_return_type = false;
|
||||||
}
|
}
|
||||||
@ -163,8 +169,7 @@ std::string LexWordAroundPos(lsPosition position, const std::string& content) {
|
|||||||
char c = content[start - 1];
|
char c = content[start - 1];
|
||||||
if (isalnum(c) || c == '_') {
|
if (isalnum(c) || c == '_') {
|
||||||
--start;
|
--start;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,8 +178,7 @@ std::string LexWordAroundPos(lsPosition position, const std::string& content) {
|
|||||||
char c = content[end + 1];
|
char c = content[end + 1];
|
||||||
if (isalnum(c) || c == '_') {
|
if (isalnum(c) || c == '_') {
|
||||||
++end;
|
++end;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,18 +4,23 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
// Utility method to map |position| to an offset inside of |content|.
|
// Utility method to map |position| to an offset inside of |content|.
|
||||||
int GetOffsetForPosition(lsPosition position, const std::string& content);
|
int GetOffsetForPosition(lsPosition position, const std::string& content);
|
||||||
// Utility method to find a position for the given character.
|
// Utility method to find a position for the given character.
|
||||||
lsPosition CharPos(const std::string& search, char character, int character_offset = 0);
|
lsPosition CharPos(const std::string& search,
|
||||||
|
char character,
|
||||||
|
int character_offset = 0);
|
||||||
|
|
||||||
bool ShouldRunIncludeCompletion(const std::string& line);
|
bool ShouldRunIncludeCompletion(const std::string& line);
|
||||||
|
|
||||||
// TODO: eliminate |line_number| param.
|
// TODO: eliminate |line_number| param.
|
||||||
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);
|
optional<lsRange> ExtractQuotedRange(int line_number, const std::string& line);
|
||||||
|
|
||||||
void LexFunctionDeclaration(const std::string& buffer_content, lsPosition declaration_spelling, optional<std::string> type_name, std::string* insert_text, int* newlines_after_name);
|
void LexFunctionDeclaration(const std::string& buffer_content,
|
||||||
|
lsPosition declaration_spelling,
|
||||||
|
optional<std::string> type_name,
|
||||||
|
std::string* insert_text,
|
||||||
|
int* newlines_after_name);
|
||||||
|
|
||||||
std::string LexWordAroundPos(lsPosition position, const std::string& content);
|
std::string LexWordAroundPos(lsPosition position, const std::string& content);
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
#define CURSOR_H_
|
#define CURSOR_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
#include <clang-c/Index.h>
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
#include "TranslationUnit.h"
|
#include "TranslationUnit.h"
|
||||||
|
|
||||||
#include "Utility.h"
|
|
||||||
#include "../platform.h"
|
#include "../platform.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
#include "Utility.h"
|
||||||
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
namespace clang {
|
namespace clang {
|
||||||
|
|
||||||
@ -24,10 +26,12 @@ TranslationUnit::TranslationUnit(Index* index,
|
|||||||
for (const auto& arg : platform_args)
|
for (const auto& arg : platform_args)
|
||||||
args.push_back(arg.c_str());
|
args.push_back(arg.c_str());
|
||||||
|
|
||||||
//std::cerr << "Parsing " << filepath << " with args " << StringJoin(args) << std::endl;
|
// std::cerr << "Parsing " << filepath << " with args " << StringJoin(args) <<
|
||||||
|
// std::endl;
|
||||||
|
|
||||||
//cx_tu = clang_createTranslationUnitFromSourceFile(
|
// cx_tu = clang_createTranslationUnitFromSourceFile(
|
||||||
// index->cx_index, filepath.c_str(), args.size(), args.data(), (unsigned)unsaved_files.size(), unsaved_files.data());
|
// index->cx_index, filepath.c_str(), args.size(), args.data(),
|
||||||
|
// (unsigned)unsaved_files.size(), unsaved_files.data());
|
||||||
|
|
||||||
CXErrorCode error_code = clang_parseTranslationUnit2(
|
CXErrorCode error_code = clang_parseTranslationUnit2(
|
||||||
index->cx_index, filepath.c_str(), args.data(), (int)args.size(),
|
index->cx_index, filepath.c_str(), args.data(), (int)args.size(),
|
||||||
@ -38,20 +42,23 @@ TranslationUnit::TranslationUnit(Index* index,
|
|||||||
did_fail = false;
|
did_fail = false;
|
||||||
break;
|
break;
|
||||||
case CXError_Failure:
|
case CXError_Failure:
|
||||||
std::cerr << "libclang generic failure for " << filepath << " with args " << StringJoin(args) << std::endl;
|
std::cerr << "libclang generic failure for " << filepath << " with args "
|
||||||
|
<< StringJoin(args) << std::endl;
|
||||||
did_fail = true;
|
did_fail = true;
|
||||||
break;
|
break;
|
||||||
case CXError_Crashed:
|
case CXError_Crashed:
|
||||||
std::cerr << "libclang crashed for " << filepath << " with args " << StringJoin(args) << std::endl;
|
std::cerr << "libclang crashed for " << filepath << " with args "
|
||||||
|
<< StringJoin(args) << std::endl;
|
||||||
did_fail = true;
|
did_fail = true;
|
||||||
break;
|
break;
|
||||||
case CXError_InvalidArguments:
|
case CXError_InvalidArguments:
|
||||||
std::cerr << "libclang had invalid arguments for " << " with args " << StringJoin(args) << filepath
|
std::cerr << "libclang had invalid arguments for "
|
||||||
<< std::endl;
|
<< " with args " << StringJoin(args) << filepath << std::endl;
|
||||||
did_fail = true;
|
did_fail = true;
|
||||||
break;
|
break;
|
||||||
case CXError_ASTReadError:
|
case CXError_ASTReadError:
|
||||||
std::cerr << "libclang had ast read error for " << filepath << " with args " << StringJoin(args) << std::endl;
|
std::cerr << "libclang had ast read error for " << filepath
|
||||||
|
<< " with args " << StringJoin(args) << std::endl;
|
||||||
did_fail = true;
|
did_fail = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -63,9 +70,9 @@ TranslationUnit::~TranslationUnit() {
|
|||||||
|
|
||||||
void TranslationUnit::ReparseTranslationUnit(
|
void TranslationUnit::ReparseTranslationUnit(
|
||||||
std::vector<CXUnsavedFile>& unsaved) {
|
std::vector<CXUnsavedFile>& unsaved) {
|
||||||
int error_code =
|
int error_code = clang_reparseTranslationUnit(
|
||||||
clang_reparseTranslationUnit(cx_tu, (unsigned)unsaved.size(), unsaved.data(),
|
cx_tu, (unsigned)unsaved.size(), unsaved.data(),
|
||||||
clang_defaultReparseOptions(cx_tu));
|
clang_defaultReparseOptions(cx_tu));
|
||||||
switch (error_code) {
|
switch (error_code) {
|
||||||
case CXError_Success:
|
case CXError_Success:
|
||||||
did_fail = false;
|
did_fail = false;
|
||||||
@ -92,4 +99,4 @@ void TranslationUnit::ReparseTranslationUnit(
|
|||||||
Cursor TranslationUnit::document_cursor() const {
|
Cursor TranslationUnit::document_cursor() const {
|
||||||
return Cursor(clang_getTranslationUnitCursor(cx_tu));
|
return Cursor(clang_getTranslationUnitCursor(cx_tu));
|
||||||
}
|
}
|
||||||
}
|
} // namespace clang
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include "Index.h"
|
|
||||||
#include "Cursor.h"
|
#include "Cursor.h"
|
||||||
|
#include "Index.h"
|
||||||
|
|
||||||
|
|
||||||
#include <clang-c/Index.h>
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
|
40
src/match.cc
40
src/match.cc
@ -21,33 +21,31 @@ optional<Matcher> Matcher::Create(const std::string& search) {
|
|||||||
try {
|
try {
|
||||||
Matcher m;
|
Matcher m;
|
||||||
m.regex_string = search;
|
m.regex_string = search;
|
||||||
m.regex = std::regex(search,
|
m.regex = std::regex(
|
||||||
std::regex_constants::ECMAScript |
|
search, std::regex_constants::ECMAScript | std::regex_constants::icase |
|
||||||
std::regex_constants::icase |
|
std::regex_constants::optimize
|
||||||
std::regex_constants::optimize
|
// std::regex_constants::nosubs
|
||||||
//std::regex_constants::nosubs
|
|
||||||
);
|
);
|
||||||
return m;
|
return m;
|
||||||
}
|
} catch (std::exception e) {
|
||||||
catch (std::exception e) {
|
|
||||||
Out_ShowLogMessage out;
|
Out_ShowLogMessage out;
|
||||||
out.display_type = Out_ShowLogMessage::DisplayType::Show;
|
out.display_type = Out_ShowLogMessage::DisplayType::Show;
|
||||||
out.params.type = lsMessageType::Error;
|
out.params.type = lsMessageType::Error;
|
||||||
out.params.message = "cquery: Parsing EMCAScript regex \"" + search + "\" failed; " + e.what();
|
out.params.message = "cquery: Parsing EMCAScript regex \"" + search +
|
||||||
|
"\" failed; " + e.what();
|
||||||
IpcManager::instance()->SendOutMessageToClient(IpcId::Cout, out);
|
IpcManager::instance()->SendOutMessageToClient(IpcId::Cout, out);
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Matcher::IsMatch(const std::string& value) const {
|
bool Matcher::IsMatch(const std::string& value) const {
|
||||||
//std::smatch match;
|
// std::smatch match;
|
||||||
//return std::regex_match(value, match, regex);
|
// return std::regex_match(value, match, regex);
|
||||||
return std::regex_match(value, regex, std::regex_constants::match_any);
|
return std::regex_match(value, regex, std::regex_constants::match_any);
|
||||||
}
|
}
|
||||||
|
|
||||||
GroupMatch::GroupMatch(
|
GroupMatch::GroupMatch(const std::vector<std::string>& whitelist,
|
||||||
const std::vector<std::string>& whitelist,
|
const std::vector<std::string>& blacklist) {
|
||||||
const std::vector<std::string>& blacklist) {
|
|
||||||
for (const std::string& entry : whitelist) {
|
for (const std::string& entry : whitelist) {
|
||||||
optional<Matcher> m = Matcher::Create(entry);
|
optional<Matcher> m = Matcher::Create(entry);
|
||||||
if (m)
|
if (m)
|
||||||
@ -60,7 +58,8 @@ GroupMatch::GroupMatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupMatch::IsMatch(const std::string& value, std::string* match_failure_reason) const {
|
bool GroupMatch::IsMatch(const std::string& value,
|
||||||
|
std::string* match_failure_reason) const {
|
||||||
for (const Matcher& m : whitelist) {
|
for (const Matcher& m : whitelist) {
|
||||||
if (!m.IsMatch(value)) {
|
if (!m.IsMatch(value)) {
|
||||||
if (match_failure_reason)
|
if (match_failure_reason)
|
||||||
@ -80,17 +79,16 @@ bool GroupMatch::IsMatch(const std::string& value, std::string* match_failure_re
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_SUITE("Matcher");
|
TEST_SUITE("Matcher");
|
||||||
|
|
||||||
TEST_CASE("sanity") {
|
TEST_CASE("sanity") {
|
||||||
//Matcher m("abc");
|
// Matcher m("abc");
|
||||||
// TODO: check case
|
// TODO: check case
|
||||||
//CHECK(m.IsMatch("abc"));
|
// CHECK(m.IsMatch("abc"));
|
||||||
//CHECK(m.IsMatch("fooabc"));
|
// CHECK(m.IsMatch("fooabc"));
|
||||||
//CHECK(m.IsMatch("abc"));
|
// CHECK(m.IsMatch("abc"));
|
||||||
//CHECK(m.IsMatch("abcfoo"));
|
// CHECK(m.IsMatch("abcfoo"));
|
||||||
//CHECK(m.IsMatch("11a11b11c11"));
|
// CHECK(m.IsMatch("11a11b11c11"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
struct Matcher {
|
struct Matcher {
|
||||||
static optional<Matcher> Create(const std::string& search);
|
static optional<Matcher> Create(const std::string& search);
|
||||||
@ -23,7 +23,8 @@ struct GroupMatch {
|
|||||||
GroupMatch(const std::vector<std::string>& whitelist,
|
GroupMatch(const std::vector<std::string>& whitelist,
|
||||||
const std::vector<std::string>& blacklist);
|
const std::vector<std::string>& blacklist);
|
||||||
|
|
||||||
bool IsMatch(const std::string& value, 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> whitelist;
|
||||||
std::vector<Matcher> blacklist;
|
std::vector<Matcher> blacklist;
|
||||||
|
@ -162,7 +162,6 @@ MessageQueue::MessageQueue(std::unique_ptr<Buffer> buffer, bool buffer_has_data)
|
|||||||
|
|
||||||
local_buffer_ = Buffer::Create(buffer_->capacity - sizeof(BufferMetadata));
|
local_buffer_ = Buffer::Create(buffer_->capacity - sizeof(BufferMetadata));
|
||||||
memset(local_buffer_->data, 0, local_buffer_->capacity);
|
memset(local_buffer_->data, 0, local_buffer_->capacity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageQueue::Enqueue(const Message& message) {
|
void MessageQueue::Enqueue(const Message& message) {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> ParseOptions(int argc,
|
std::unordered_map<std::string, std::string> ParseOptions(int argc,
|
||||||
char** argv) {
|
char** argv) {
|
||||||
std::unordered_map<std::string, std::string> output;
|
std::unordered_map<std::string, std::string> output;
|
||||||
|
|
||||||
std::string previous_arg;
|
std::string previous_arg;
|
||||||
@ -14,14 +14,13 @@ std::unordered_map<std::string, std::string> ParseOptions(int argc,
|
|||||||
if (arg[0] != '-') {
|
if (arg[0] != '-') {
|
||||||
if (previous_arg.size() == 0) {
|
if (previous_arg.size() == 0) {
|
||||||
std::cerr << "Invalid arguments; switches must start with -"
|
std::cerr << "Invalid arguments; switches must start with -"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
output[previous_arg] = arg;
|
output[previous_arg] = arg;
|
||||||
previous_arg = "";
|
previous_arg = "";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
output[arg] = "";
|
output[arg] = "";
|
||||||
previous_arg = arg;
|
previous_arg = arg;
|
||||||
}
|
}
|
||||||
@ -31,6 +30,6 @@ std::unordered_map<std::string, std::string> ParseOptions(int argc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HasOption(const std::unordered_map<std::string, std::string>& options,
|
bool HasOption(const std::unordered_map<std::string, std::string>& options,
|
||||||
const std::string& option) {
|
const std::string& option) {
|
||||||
return options.find(option) != options.end();
|
return options.find(option) != options.end();
|
||||||
}
|
}
|
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> ParseOptions(
|
std::unordered_map<std::string, std::string> ParseOptions(int argc,
|
||||||
int argc,
|
char** argv);
|
||||||
char** argv);
|
|
||||||
|
|
||||||
bool HasOption(
|
bool HasOption(const std::unordered_map<std::string, std::string>& options,
|
||||||
const std::unordered_map<std::string, std::string>& options,
|
const std::string& option);
|
||||||
const std::string& option);
|
|
@ -22,8 +22,14 @@ struct PerformanceImportFile {
|
|||||||
// [indexer] create delta IndexUpdate object
|
// [indexer] create delta IndexUpdate object
|
||||||
uint64_t index_make_delta = 0;
|
uint64_t index_make_delta = 0;
|
||||||
// [querydb] update WorkingFile indexed file state
|
// [querydb] update WorkingFile indexed file state
|
||||||
//uint64_t querydb_update_working_file = 0;
|
// uint64_t querydb_update_working_file = 0;
|
||||||
// [querydb] apply IndexUpdate
|
// [querydb] apply IndexUpdate
|
||||||
//uint64_t querydb_apply_index_update = 0;
|
// uint64_t querydb_apply_index_update = 0;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(PerformanceImportFile, index_parse, index_build, querydb_id_map, index_save_to_disk, index_load_cached, index_make_delta);
|
MAKE_REFLECT_STRUCT(PerformanceImportFile,
|
||||||
|
index_parse,
|
||||||
|
index_build,
|
||||||
|
querydb_id_map,
|
||||||
|
index_save_to_disk,
|
||||||
|
index_load_cached,
|
||||||
|
index_make_delta);
|
@ -2,18 +2,19 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// See http://stackoverflow.com/a/236803
|
// See http://stackoverflow.com/a/236803
|
||||||
template<typename Out>
|
template <typename Out>
|
||||||
void Split(const std::string &s, char delim, Out result) {
|
void Split(const std::string& s, char delim, Out result) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss.str(s);
|
ss.str(s);
|
||||||
std::string item;
|
std::string item;
|
||||||
@ -22,7 +23,7 @@ void Split(const std::string &s, char delim, Out result) {
|
|||||||
*(result++) = item;
|
*(result++) = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<std::string> Split(const std::string &s, char delim) {
|
std::vector<std::string> Split(const std::string& s, char delim) {
|
||||||
std::vector<std::string> elems;
|
std::vector<std::string> elems;
|
||||||
Split(s, delim, std::back_inserter(elems));
|
Split(s, delim, std::back_inserter(elems));
|
||||||
return elems;
|
return elems;
|
||||||
@ -70,14 +71,16 @@ void MakeDirectoryRecursive(std::string path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (first_success == -1) {
|
if (first_success == -1) {
|
||||||
std::cerr << "Failed to make any parent directory for " << path << std::endl;
|
std::cerr << "Failed to make any parent directory for " << path
|
||||||
|
<< std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make all child directories.
|
// Make all child directories.
|
||||||
for (int i = first_success + 1; i <= components.size(); ++i) {
|
for (int i = first_success + 1; i <= components.size(); ++i) {
|
||||||
if (TryMakeDirectory(prefix + Join(components, '/', i)) == false) {
|
if (TryMakeDirectory(prefix + Join(components, '/', i)) == false) {
|
||||||
std::cerr << "Failed making directory for " << path << " even after creating parent directories" << std::endl;
|
std::cerr << "Failed making directory for " << path
|
||||||
|
<< " even after creating parent directories" << std::endl;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
struct PlatformMutex {
|
struct PlatformMutex {
|
||||||
virtual ~PlatformMutex();
|
virtual ~PlatformMutex();
|
||||||
|
@ -6,34 +6,39 @@
|
|||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <cassert>
|
|
||||||
#include <string>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <semaphore.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <semaphore.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/types.h> // required for stat.h
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h> // required for stat.h
|
||||||
|
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <fcntl.h> /* For O_* constants */
|
|
||||||
#include <sys/stat.h> /* For mode constants */
|
#include <fcntl.h> /* For O_* constants */
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h> /* For mode constants */
|
||||||
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
@ -85,8 +90,9 @@ struct PlatformSharedMemoryLinux : public PlatformSharedMemory {
|
|||||||
int fd_;
|
int fd_;
|
||||||
|
|
||||||
PlatformSharedMemoryLinux(const std::string& name, size_t size)
|
PlatformSharedMemoryLinux(const std::string& name, size_t size)
|
||||||
: name_(name), size_(size) {
|
: name_(name), size_(size) {
|
||||||
std::cerr << "PlatformSharedMemoryLinux name=" << name << ", size=" << size << std::endl;
|
std::cerr << "PlatformSharedMemoryLinux name=" << name << ", size=" << size
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
// Try to create shared memory but only if it does not already exist. Since
|
// Try to create shared memory but only if it does not already exist. Since
|
||||||
// we created the memory, we need to initialize it.
|
// we created the memory, we need to initialize it.
|
||||||
@ -105,9 +111,8 @@ struct PlatformSharedMemoryLinux : public PlatformSharedMemory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map the shared memory to an address.
|
// Map the shared memory to an address.
|
||||||
data =
|
data = CHECKED(mmap(nullptr /*kernel assigned starting address*/, size,
|
||||||
CHECKED(mmap(nullptr /*kernel assigned starting address*/, size,
|
PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0 /*offset*/));
|
||||||
PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0 /*offset*/));
|
|
||||||
capacity = size;
|
capacity = size;
|
||||||
|
|
||||||
std::cerr << "Open shared memory name=" << name << ", fd=" << fd_
|
std::cerr << "Open shared memory name=" << name << ", fd=" << fd_
|
||||||
@ -134,13 +139,13 @@ std::unique_ptr<PlatformScopedMutexLock> CreatePlatformScopedMutexLock(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
|
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
|
||||||
const std::string& name, size_t size) {
|
const std::string& name,
|
||||||
|
size_t size) {
|
||||||
std::string name2 = "/" + name;
|
std::string name2 = "/" + name;
|
||||||
return MakeUnique<PlatformSharedMemoryLinux>(name2, size);
|
return MakeUnique<PlatformSharedMemoryLinux>(name2, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlatformInit() {
|
void PlatformInit() {}
|
||||||
}
|
|
||||||
|
|
||||||
std::string NormalizePath(const std::string& path) {
|
std::string NormalizePath(const std::string& path) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -152,7 +157,7 @@ std::string NormalizePath(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TryMakeDirectory(const std::string& absolute_path) {
|
bool TryMakeDirectory(const std::string& absolute_path) {
|
||||||
const mode_t kMode = 0777; // UNIX style permissions
|
const mode_t kMode = 0777; // UNIX style permissions
|
||||||
if (mkdir(absolute_path.c_str(), kMode) == -1) {
|
if (mkdir(absolute_path.c_str(), kMode) == -1) {
|
||||||
// Success if the directory exists.
|
// Success if the directory exists.
|
||||||
return errno == EEXIST;
|
return errno == EEXIST;
|
||||||
@ -172,14 +177,16 @@ optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
|||||||
if (stat(absolute_path.c_str(), &buf) != 0) {
|
if (stat(absolute_path.c_str(), &buf) != 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
//std::cerr << "GetLastModificationTime: unable to find file " << absolute_path << std::endl;
|
// std::cerr << "GetLastModificationTime: unable to find file " <<
|
||||||
|
// absolute_path << std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
//std::cerr << "GetLastModificationTime: invalid param to _stat for file file " << absolute_path << std::endl;
|
// std::cerr << "GetLastModificationTime: invalid param to _stat for
|
||||||
|
// file file " << absolute_path << std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
default:
|
default:
|
||||||
//std::cerr << "GetLastModificationTime: unhandled for " << absolute_path << std::endl;
|
// std::cerr << "GetLastModificationTime: unhandled for " <<
|
||||||
//exit(1);
|
// absolute_path << std::endl; exit(1);
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +212,7 @@ void CopyFileTo(const std::string& dest, const std::string& source) {
|
|||||||
char buf[4096];
|
char buf[4096];
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
while (nread = read(fd_from, buf, sizeof buf), nread > 0) {
|
while (nread = read(fd_from, buf, sizeof buf), nread > 0) {
|
||||||
char *out_ptr = buf;
|
char* out_ptr = buf;
|
||||||
ssize_t nwritten;
|
ssize_t nwritten;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -214,8 +221,7 @@ void CopyFileTo(const std::string& dest, const std::string& source) {
|
|||||||
if (nwritten >= 0) {
|
if (nwritten >= 0) {
|
||||||
nread -= nwritten;
|
nread -= nwritten;
|
||||||
out_ptr += nwritten;
|
out_ptr += nwritten;
|
||||||
}
|
} else if (errno != EINTR)
|
||||||
else if (errno != EINTR)
|
|
||||||
goto out_error;
|
goto out_error;
|
||||||
} while (nread > 0);
|
} while (nread > 0);
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,15 @@
|
|||||||
|
|
||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -23,21 +25,21 @@ namespace {
|
|||||||
DWORD CheckForError(std::vector<DWORD> allow) {
|
DWORD CheckForError(std::vector<DWORD> allow) {
|
||||||
DWORD error = GetLastError();
|
DWORD error = GetLastError();
|
||||||
if (error == ERROR_SUCCESS ||
|
if (error == ERROR_SUCCESS ||
|
||||||
std::find(allow.begin(), allow.end(), error) != allow.end())
|
std::find(allow.begin(), allow.end(), error) != allow.end())
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// See http://stackoverflow.com/a/17387176
|
// See http://stackoverflow.com/a/17387176
|
||||||
LPSTR message_buffer = nullptr;
|
LPSTR message_buffer = nullptr;
|
||||||
size_t size = FormatMessageA(
|
size_t size = FormatMessageA(
|
||||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
(LPSTR)&message_buffer, 0, NULL);
|
(LPSTR)&message_buffer, 0, NULL);
|
||||||
std::string message(message_buffer, size);
|
std::string message(message_buffer, size);
|
||||||
LocalFree(message_buffer);
|
LocalFree(message_buffer);
|
||||||
|
|
||||||
std::cerr << "Windows error code=" << error << ", message=" << message
|
std::cerr << "Windows error code=" << error << ", message=" << message
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
assert(false); // debugger break
|
assert(false); // debugger break
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -49,7 +51,7 @@ struct PlatformMutexWin : public PlatformMutex {
|
|||||||
PlatformMutexWin(const std::string& name) {
|
PlatformMutexWin(const std::string& name) {
|
||||||
std::cerr << "[win] Creating mutex with name " << name << std::endl;
|
std::cerr << "[win] Creating mutex with name " << name << std::endl;
|
||||||
raw_mutex = CreateMutex(nullptr, false /*initial_owner*/, name.c_str());
|
raw_mutex = CreateMutex(nullptr, false /*initial_owner*/, name.c_str());
|
||||||
CheckForError({ ERROR_ALREADY_EXISTS });
|
CheckForError({ERROR_ALREADY_EXISTS});
|
||||||
}
|
}
|
||||||
|
|
||||||
~PlatformMutexWin() override {
|
~PlatformMutexWin() override {
|
||||||
@ -65,12 +67,12 @@ struct PlatformScopedMutexLockWin : public PlatformScopedMutexLock {
|
|||||||
PlatformScopedMutexLockWin(HANDLE raw_mutex) : raw_mutex(raw_mutex) {
|
PlatformScopedMutexLockWin(HANDLE raw_mutex) : raw_mutex(raw_mutex) {
|
||||||
DWORD result = WaitForSingleObject(raw_mutex, INFINITE);
|
DWORD result = WaitForSingleObject(raw_mutex, INFINITE);
|
||||||
assert(result == WAIT_OBJECT_0);
|
assert(result == WAIT_OBJECT_0);
|
||||||
CheckForError({ ERROR_NO_MORE_FILES, ERROR_ALREADY_EXISTS } /*allow*/);
|
CheckForError({ERROR_NO_MORE_FILES, ERROR_ALREADY_EXISTS} /*allow*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
~PlatformScopedMutexLockWin() override {
|
~PlatformScopedMutexLockWin() override {
|
||||||
ReleaseMutex(raw_mutex);
|
ReleaseMutex(raw_mutex);
|
||||||
CheckForError({ ERROR_NO_MORE_FILES, ERROR_ALREADY_EXISTS } /*allow*/);
|
CheckForError({ERROR_NO_MORE_FILES, ERROR_ALREADY_EXISTS} /*allow*/);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,15 +81,15 @@ struct PlatformSharedMemoryWin : public PlatformSharedMemory {
|
|||||||
|
|
||||||
PlatformSharedMemoryWin(const std::string& name, size_t capacity) {
|
PlatformSharedMemoryWin(const std::string& name, size_t capacity) {
|
||||||
std::cerr << "[win] Creating shared memory with name " << name
|
std::cerr << "[win] Creating shared memory with name " << name
|
||||||
<< " and capacity " << capacity << std::endl;
|
<< " and capacity " << capacity << std::endl;
|
||||||
this->name = name;
|
this->name = name;
|
||||||
|
|
||||||
shmem_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
shmem_ = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||||
(DWORD)capacity, name.c_str());
|
(DWORD)capacity, name.c_str());
|
||||||
CheckForError({ ERROR_ALREADY_EXISTS } /*allow*/);
|
CheckForError({ERROR_ALREADY_EXISTS} /*allow*/);
|
||||||
|
|
||||||
data = MapViewOfFile(shmem_, FILE_MAP_ALL_ACCESS, 0, 0, capacity);
|
data = MapViewOfFile(shmem_, FILE_MAP_ALL_ACCESS, 0, 0, capacity);
|
||||||
CheckForError({ ERROR_ALREADY_EXISTS } /*allow*/);
|
CheckForError({ERROR_ALREADY_EXISTS} /*allow*/);
|
||||||
|
|
||||||
this->capacity = capacity;
|
this->capacity = capacity;
|
||||||
}
|
}
|
||||||
@ -108,14 +110,14 @@ std::unique_ptr<PlatformMutex> CreatePlatformMutex(const std::string& name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PlatformScopedMutexLock> CreatePlatformScopedMutexLock(
|
std::unique_ptr<PlatformScopedMutexLock> CreatePlatformScopedMutexLock(
|
||||||
PlatformMutex* mutex) {
|
PlatformMutex* mutex) {
|
||||||
return MakeUnique<PlatformScopedMutexLockWin>(
|
return MakeUnique<PlatformScopedMutexLockWin>(
|
||||||
static_cast<PlatformMutexWin*>(mutex)->raw_mutex);
|
static_cast<PlatformMutexWin*>(mutex)->raw_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
|
std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
return MakeUnique<PlatformSharedMemoryWin>(name, size);
|
return MakeUnique<PlatformSharedMemoryWin>(name, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +139,7 @@ std::string NormalizePath(const std::string& path) {
|
|||||||
DWORD retval = 0;
|
DWORD retval = 0;
|
||||||
TCHAR buffer[MAX_PATH] = TEXT("");
|
TCHAR buffer[MAX_PATH] = TEXT("");
|
||||||
TCHAR buf[MAX_PATH] = TEXT("");
|
TCHAR buf[MAX_PATH] = TEXT("");
|
||||||
TCHAR** lpp_part = { NULL };
|
TCHAR** lpp_part = {NULL};
|
||||||
|
|
||||||
retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part);
|
retval = GetFullPathName(path.c_str(), MAX_PATH, buffer, lpp_part);
|
||||||
// fail, return original
|
// fail, return original
|
||||||
@ -146,7 +148,7 @@ std::string NormalizePath(const std::string& path) {
|
|||||||
|
|
||||||
std::string result = buffer;
|
std::string result = buffer;
|
||||||
std::replace(result.begin(), result.end(), '\\', '/');
|
std::replace(result.begin(), result.end(), '\\', '/');
|
||||||
//std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
// std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,13 +162,12 @@ bool TryMakeDirectory(const std::string& absolute_path) {
|
|||||||
|
|
||||||
// See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
// See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
||||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||||
#pragma pack(push,8)
|
#pragma pack(push, 8)
|
||||||
typedef struct tagTHREADNAME_INFO
|
typedef struct tagTHREADNAME_INFO {
|
||||||
{
|
DWORD dwType; // Must be 0x1000.
|
||||||
DWORD dwType; // Must be 0x1000.
|
LPCSTR szName; // Pointer to name (in user addr space).
|
||||||
LPCSTR szName; // Pointer to name (in user addr space).
|
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
|
||||||
} THREADNAME_INFO;
|
} THREADNAME_INFO;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
void SetCurrentThreadName(const std::string& thread_name) {
|
void SetCurrentThreadName(const std::string& thread_name) {
|
||||||
@ -179,9 +180,10 @@ void SetCurrentThreadName(const std::string& thread_name) {
|
|||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
|
|
||||||
__try {
|
__try {
|
||||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
|
||||||
|
(ULONG_PTR*)&info);
|
||||||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||||
}
|
}
|
||||||
__except (EXCEPTION_EXECUTE_HANDLER) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
||||||
@ -189,14 +191,16 @@ optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
|||||||
if (_stat(absolute_path.c_str(), &buf) != 0) {
|
if (_stat(absolute_path.c_str(), &buf) != 0) {
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
//std::cerr << "GetLastModificationTime: unable to find file " << absolute_path << std::endl;
|
// std::cerr << "GetLastModificationTime: unable to find file " <<
|
||||||
|
// absolute_path << std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
//std::cerr << "GetLastModificationTime: invalid param to _stat for file file " << absolute_path << std::endl;
|
// std::cerr << "GetLastModificationTime: invalid param to _stat for
|
||||||
|
// file file " << absolute_path << std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
default:
|
default:
|
||||||
//std::cerr << "GetLastModificationTime: unhandled for " << absolute_path << std::endl;
|
// std::cerr << "GetLastModificationTime: unhandled for " <<
|
||||||
//exit(1);
|
// absolute_path << std::endl; exit(1);
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,15 +209,11 @@ optional<int64_t> GetLastModificationTime(const std::string& absolute_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MoveFileTo(const std::string& destination, const std::string& source) {
|
void MoveFileTo(const std::string& destination, const std::string& source) {
|
||||||
MoveFile(source.c_str(),
|
MoveFile(source.c_str(), destination.c_str());
|
||||||
destination.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyFileTo(const std::string& destination, const std::string& source) {
|
void CopyFileTo(const std::string& destination, const std::string& source) {
|
||||||
CopyFile(
|
CopyFile(source.c_str(), destination.c_str(), false /*failIfExists*/);
|
||||||
source.c_str(),
|
|
||||||
destination.c_str(),
|
|
||||||
false /*failIfExists*/);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSymLink(const std::string& path) {
|
bool IsSymLink(const std::string& path) {
|
||||||
@ -221,10 +221,7 @@ bool IsSymLink(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> GetPlatformClangArguments() {
|
std::vector<std::string> GetPlatformClangArguments() {
|
||||||
return {
|
return {"-fms-compatibility", "-fdelayed-template-parsing"};
|
||||||
"-fms-compatibility",
|
|
||||||
"-fdelayed-template-parsing"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeUnusedMemory() {}
|
void FreeUnusedMemory() {}
|
||||||
|
@ -12,8 +12,7 @@ const char* SkipAfter(const char* input, char skip_after) {
|
|||||||
|
|
||||||
Position::Position() {}
|
Position::Position() {}
|
||||||
|
|
||||||
Position::Position(int16_t line, int16_t column)
|
Position::Position(int16_t line, int16_t column) : line(line), column(column) {}
|
||||||
: line(line), column(column) {}
|
|
||||||
|
|
||||||
Position::Position(const char* encoded) {
|
Position::Position(const char* encoded) {
|
||||||
assert(encoded);
|
assert(encoded);
|
||||||
@ -61,7 +60,9 @@ bool Position::operator==(const Position& that) const {
|
|||||||
return line == that.line && column == that.column;
|
return line == that.line && column == that.column;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Position::operator!=(const Position& that) const { return !(*this == that); }
|
bool Position::operator!=(const Position& that) const {
|
||||||
|
return !(*this == that);
|
||||||
|
}
|
||||||
|
|
||||||
bool Position::operator<(const Position& that) const {
|
bool Position::operator<(const Position& that) const {
|
||||||
if (line < that.line)
|
if (line < that.line)
|
||||||
@ -133,7 +134,9 @@ bool Range::operator==(const Range& that) const {
|
|||||||
return start == that.start && end == that.end;
|
return start == that.start && end == that.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Range::operator!=(const Range& that) const { return !(*this == that); }
|
bool Range::operator!=(const Range& that) const {
|
||||||
|
return !(*this == that);
|
||||||
|
}
|
||||||
|
|
||||||
bool Range::operator<(const Range& that) const {
|
bool Range::operator<(const Range& that) const {
|
||||||
if (start < that.start)
|
if (start < that.start)
|
||||||
@ -150,7 +153,6 @@ void Reflect(Writer& visitor, Position& value) {
|
|||||||
visitor.String(output.c_str(), (rapidjson::SizeType)output.size());
|
visitor.String(output.c_str(), (rapidjson::SizeType)output.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Range
|
// Range
|
||||||
void Reflect(Reader& visitor, Range& value) {
|
void Reflect(Reader& visitor, Range& value) {
|
||||||
value = Range(visitor.GetString());
|
value = Range(visitor.GetString());
|
||||||
|
@ -24,7 +24,9 @@ struct Position {
|
|||||||
bool operator!=(const Position& that) const;
|
bool operator!=(const Position& that) const;
|
||||||
bool operator<(const Position& that) const;
|
bool operator<(const Position& that) const;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Position) == 4, "Investigate, Position should be 32-bits for indexer size reasons");
|
static_assert(
|
||||||
|
sizeof(Position) == 4,
|
||||||
|
"Investigate, Position should be 32-bits for indexer size reasons");
|
||||||
MAKE_HASHABLE(Position, t.line, t.column);
|
MAKE_HASHABLE(Position, t.line, t.column);
|
||||||
|
|
||||||
struct Range {
|
struct Range {
|
||||||
|
252
src/project.cc
252
src/project.cc
@ -1,11 +1,12 @@
|
|||||||
#include "project.h"
|
#include "project.h"
|
||||||
|
|
||||||
#include "match.h"
|
|
||||||
#include "libclangmm/Utility.h"
|
#include "libclangmm/Utility.h"
|
||||||
|
#include "match.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
#include <clang-c/CXCompilationDatabase.h>
|
#include <clang-c/CXCompilationDatabase.h>
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
@ -26,79 +27,40 @@ MAKE_REFLECT_STRUCT(CompileCommandsEntry, directory, file, command, args);
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
static const char* kBlacklistMulti[] = {"-MF", "-Xclang"};
|
||||||
static const char* kBlacklistMulti[] = {
|
|
||||||
"-MF",
|
|
||||||
"-Xclang"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Blacklisted flags which are always removed from the command line.
|
// Blacklisted flags which are always removed from the command line.
|
||||||
static const char *kBlacklist[] = {
|
static const char* kBlacklist[] = {
|
||||||
"--param",
|
"--param", "-M", "-MD", "-MG", "-MM", "-MMD", "-MP", "-MQ", "-MT", "-Og",
|
||||||
"-M",
|
"-Wa,--32", "-Wa,--64", "-Wl,--incremental-full",
|
||||||
"-MD",
|
"-Wl,--incremental-patch,1", "-Wl,--no-incremental",
|
||||||
"-MG",
|
"-fbuild-session-file=", "-fbuild-session-timestamp=", "-fembed-bitcode",
|
||||||
"-MM",
|
"-fembed-bitcode-marker", "-fmodules-validate-once-per-build-session",
|
||||||
"-MMD",
|
"-fno-delete-null-pointer-checks",
|
||||||
"-MP",
|
"-fno-use-linker-plugin"
|
||||||
"-MQ",
|
"-fno-var-tracking",
|
||||||
"-MT",
|
"-fno-var-tracking-assignments", "-fno-enforce-eh-specs", "-fvar-tracking",
|
||||||
"-Og",
|
"-fvar-tracking-assignments", "-fvar-tracking-assignments-toggle",
|
||||||
"-Wa,--32",
|
"-gcc-toolchain",
|
||||||
"-Wa,--64",
|
"-march=", "-masm=", "-mcpu=", "-mfpmath=", "-mtune=", "-s",
|
||||||
"-Wl,--incremental-full",
|
|
||||||
"-Wl,--incremental-patch,1",
|
|
||||||
"-Wl,--no-incremental",
|
|
||||||
"-fbuild-session-file=",
|
|
||||||
"-fbuild-session-timestamp=",
|
|
||||||
"-fembed-bitcode",
|
|
||||||
"-fembed-bitcode-marker",
|
|
||||||
"-fmodules-validate-once-per-build-session",
|
|
||||||
"-fno-delete-null-pointer-checks",
|
|
||||||
"-fno-use-linker-plugin"
|
|
||||||
"-fno-var-tracking",
|
|
||||||
"-fno-var-tracking-assignments",
|
|
||||||
"-fno-enforce-eh-specs",
|
|
||||||
"-fvar-tracking",
|
|
||||||
"-fvar-tracking-assignments",
|
|
||||||
"-fvar-tracking-assignments-toggle",
|
|
||||||
"-gcc-toolchain",
|
|
||||||
"-march=",
|
|
||||||
"-masm=",
|
|
||||||
"-mcpu=",
|
|
||||||
"-mfpmath=",
|
|
||||||
"-mtune=",
|
|
||||||
"-s",
|
|
||||||
|
|
||||||
"-B",
|
"-B",
|
||||||
//"-f",
|
//"-f",
|
||||||
//"-pipe",
|
//"-pipe",
|
||||||
//"-W",
|
//"-W",
|
||||||
// TODO: make sure we consume includes before stripping all path-like args.
|
// TODO: make sure we consume includes before stripping all path-like args.
|
||||||
"/work/goma/gomacc",
|
"/work/goma/gomacc",
|
||||||
"../../third_party/llvm-build/Release+Asserts/bin/clang++",
|
"../../third_party/llvm-build/Release+Asserts/bin/clang++",
|
||||||
"-Wno-unused-lambda-capture",
|
"-Wno-unused-lambda-capture", "/", "..",
|
||||||
"/",
|
//"-stdlib=libc++"
|
||||||
"..",
|
|
||||||
//"-stdlib=libc++"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Arguments which are followed by a potentially relative path. We need to make
|
// Arguments which are followed by a potentially relative path. We need to make
|
||||||
// all relative paths absolute, otherwise libclang will not resolve them.
|
// all relative paths absolute, otherwise libclang will not resolve them.
|
||||||
const char* kPathArgs[] = {
|
const char* kPathArgs[] = {"-I", "-iquote", "-isystem", "--sysroot="};
|
||||||
"-I",
|
|
||||||
"-iquote",
|
|
||||||
"-isystem",
|
|
||||||
"--sysroot="
|
|
||||||
};
|
|
||||||
|
|
||||||
const char* kQuoteIncludeArgs[] = {
|
const char* kQuoteIncludeArgs[] = {"-iquote"};
|
||||||
"-iquote"
|
const char* kAngleIncludeArgs[] = {"-I", "-isystem"};
|
||||||
};
|
|
||||||
const char* kAngleIncludeArgs[] = {
|
|
||||||
"-I",
|
|
||||||
"-isystem"
|
|
||||||
};
|
|
||||||
|
|
||||||
bool ShouldAddToQuoteIncludes(const std::string& arg) {
|
bool ShouldAddToQuoteIncludes(const std::string& arg) {
|
||||||
for (const char* flag_type : kQuoteIncludeArgs) {
|
for (const char* flag_type : kQuoteIncludeArgs) {
|
||||||
@ -122,8 +84,10 @@ bool IsCFile(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
||||||
std::unordered_set<std::string>& quote_includes, std::unordered_set<std::string>& angle_includes,
|
std::unordered_set<std::string>& quote_includes,
|
||||||
const std::vector<std::string>& extra_flags, const CompileCommandsEntry& entry) {
|
std::unordered_set<std::string>& angle_includes,
|
||||||
|
const std::vector<std::string>& extra_flags,
|
||||||
|
const CompileCommandsEntry& entry) {
|
||||||
Project::Entry result;
|
Project::Entry result;
|
||||||
result.filename = NormalizePath(entry.file);
|
result.filename = NormalizePath(entry.file);
|
||||||
|
|
||||||
@ -136,15 +100,15 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
|||||||
std::string arg = entry.args[i];
|
std::string arg = entry.args[i];
|
||||||
|
|
||||||
// If blacklist skip.
|
// If blacklist skip.
|
||||||
if (std::any_of(std::begin(kBlacklistMulti), std::end(kBlacklistMulti), [&arg](const char* value) {
|
if (std::any_of(
|
||||||
return StartsWith(arg, value);
|
std::begin(kBlacklistMulti), std::end(kBlacklistMulti),
|
||||||
})) {
|
[&arg](const char* value) { return StartsWith(arg, value); })) {
|
||||||
++i;
|
++i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (std::any_of(std::begin(kBlacklist), std::end(kBlacklist), [&arg](const char* value) {
|
if (std::any_of(
|
||||||
return StartsWith(arg, value);
|
std::begin(kBlacklist), std::end(kBlacklist),
|
||||||
})) {
|
[&arg](const char* value) { return StartsWith(arg, value); })) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +117,7 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
|||||||
if (arg.size() > 0 && arg[0] != '/')
|
if (arg.size() > 0 && arg[0] != '/')
|
||||||
arg = NormalizePath(entry.directory + arg);
|
arg = NormalizePath(entry.directory + arg);
|
||||||
make_next_flag_absolute = false;
|
make_next_flag_absolute = false;
|
||||||
|
|
||||||
if (add_next_flag_quote)
|
if (add_next_flag_quote)
|
||||||
quote_includes.insert(arg);
|
quote_includes.insert(arg);
|
||||||
if (add_next_flag_angle)
|
if (add_next_flag_angle)
|
||||||
@ -215,12 +179,12 @@ Project::Entry GetCompilationEntryFromCompileCommandEntry(
|
|||||||
|
|
||||||
/* TODO: Fix this function, it may be way faster than libclang's implementation.
|
/* TODO: Fix this function, it may be way faster than libclang's implementation.
|
||||||
std::vector<Project::Entry> LoadFromCompileCommandsJson(
|
std::vector<Project::Entry> LoadFromCompileCommandsJson(
|
||||||
std::unordered_set<std::string>& quote_includes, std::unordered_set<std::string>& angle_includes,
|
std::unordered_set<std::string>& quote_includes,
|
||||||
const std::vector<std::string>& extra_flags, const std::string& project_directory) {
|
std::unordered_set<std::string>& angle_includes, const std::vector<std::string>&
|
||||||
|
extra_flags, const std::string& project_directory) {
|
||||||
|
|
||||||
optional<std::string> compile_commands_content = ReadContent(project_directory + "/compile_commands.json");
|
optional<std::string> compile_commands_content = ReadContent(project_directory
|
||||||
if (!compile_commands_content)
|
+ "/compile_commands.json"); if (!compile_commands_content) return {};
|
||||||
return {};
|
|
||||||
|
|
||||||
rapidjson::Document reader;
|
rapidjson::Document reader;
|
||||||
reader.Parse(compile_commands_content->c_str());
|
reader.Parse(compile_commands_content->c_str());
|
||||||
@ -236,15 +200,18 @@ std::vector<Project::Entry> LoadFromCompileCommandsJson(
|
|||||||
if (entry.args.empty() && !entry.command.empty())
|
if (entry.args.empty() && !entry.command.empty())
|
||||||
entry.args = SplitString(entry.command, " ");
|
entry.args = SplitString(entry.command, " ");
|
||||||
|
|
||||||
result.push_back(GetCompilationEntryFromCompileCommandEntry(quote_includes, angle_includes, extra_flags, entry));
|
result.push_back(GetCompilationEntryFromCompileCommandEntry(quote_includes,
|
||||||
|
angle_includes, extra_flags, entry));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::vector<Project::Entry> LoadFromDirectoryListing(
|
std::vector<Project::Entry> LoadFromDirectoryListing(
|
||||||
std::unordered_set<std::string>& quote_includes, std::unordered_set<std::string>& angle_includes,
|
std::unordered_set<std::string>& quote_includes,
|
||||||
const std::vector<std::string>& extra_flags, const std::string& project_directory) {
|
std::unordered_set<std::string>& angle_includes,
|
||||||
|
const std::vector<std::string>& extra_flags,
|
||||||
|
const std::string& project_directory) {
|
||||||
std::vector<Project::Entry> result;
|
std::vector<Project::Entry> result;
|
||||||
|
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
@ -259,14 +226,16 @@ std::vector<Project::Entry> LoadFromDirectoryListing(
|
|||||||
}
|
}
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
|
|
||||||
|
std::vector<std::string> files = GetFilesInFolder(
|
||||||
std::vector<std::string> files = GetFilesInFolder(project_directory, true /*recursive*/, true /*add_folder_to_path*/);
|
project_directory, true /*recursive*/, true /*add_folder_to_path*/);
|
||||||
for (const std::string& file : files) {
|
for (const std::string& file : files) {
|
||||||
if (EndsWith(file, ".cc") || EndsWith(file, ".cpp") || EndsWith(file, ".c")) {
|
if (EndsWith(file, ".cc") || EndsWith(file, ".cpp") ||
|
||||||
|
EndsWith(file, ".c")) {
|
||||||
CompileCommandsEntry e;
|
CompileCommandsEntry e;
|
||||||
e.file = NormalizePath(file);
|
e.file = NormalizePath(file);
|
||||||
e.args = args;
|
e.args = args;
|
||||||
result.push_back(GetCompilationEntryFromCompileCommandEntry(quote_includes, angle_includes, extra_flags, e));
|
result.push_back(GetCompilationEntryFromCompileCommandEntry(
|
||||||
|
quote_includes, angle_includes, extra_flags, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,28 +243,38 @@ std::vector<Project::Entry> LoadFromDirectoryListing(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
||||||
std::unordered_set<std::string>& quote_includes, std::unordered_set<std::string>& angle_includes,
|
std::unordered_set<std::string>& quote_includes,
|
||||||
const std::vector<std::string>& extra_flags, const std::string& project_directory) {
|
std::unordered_set<std::string>& angle_includes,
|
||||||
|
const std::vector<std::string>& extra_flags,
|
||||||
|
const std::string& project_directory) {
|
||||||
// TODO: Figure out if this function or the clang one is faster.
|
// TODO: Figure out if this function or the clang one is faster.
|
||||||
//return LoadFromCompileCommandsJson(extra_flags, project_directory);
|
// return LoadFromCompileCommandsJson(extra_flags, project_directory);
|
||||||
|
|
||||||
std::cerr << "Trying to load compile_commands.json" << std::endl;
|
std::cerr << "Trying to load compile_commands.json" << std::endl;
|
||||||
CXCompilationDatabase_Error cx_db_load_error;
|
CXCompilationDatabase_Error cx_db_load_error;
|
||||||
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(project_directory.c_str(), &cx_db_load_error);
|
CXCompilationDatabase cx_db = clang_CompilationDatabase_fromDirectory(
|
||||||
|
project_directory.c_str(), &cx_db_load_error);
|
||||||
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
|
if (cx_db_load_error == CXCompilationDatabase_CanNotLoadDatabase) {
|
||||||
std::cerr << "Unable to load compile_commands.json located at \"" << project_directory << "\"; using directory listing instead." << std::endl;
|
std::cerr << "Unable to load compile_commands.json located at \""
|
||||||
return LoadFromDirectoryListing(quote_includes, angle_includes, extra_flags, project_directory);
|
<< project_directory << "\"; using directory listing instead."
|
||||||
|
<< std::endl;
|
||||||
|
return LoadFromDirectoryListing(quote_includes, angle_includes, extra_flags,
|
||||||
|
project_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
CXCompileCommands cx_commands = clang_CompilationDatabase_getAllCompileCommands(cx_db);
|
CXCompileCommands cx_commands =
|
||||||
|
clang_CompilationDatabase_getAllCompileCommands(cx_db);
|
||||||
|
|
||||||
unsigned int num_commands = clang_CompileCommands_getSize(cx_commands);
|
unsigned int num_commands = clang_CompileCommands_getSize(cx_commands);
|
||||||
std::vector<Project::Entry> result;
|
std::vector<Project::Entry> result;
|
||||||
for (unsigned int i = 0; i < num_commands; i++) {
|
for (unsigned int i = 0; i < num_commands; i++) {
|
||||||
CXCompileCommand cx_command = clang_CompileCommands_getCommand(cx_commands, i);
|
CXCompileCommand cx_command =
|
||||||
|
clang_CompileCommands_getCommand(cx_commands, i);
|
||||||
|
|
||||||
std::string directory = clang::ToString(clang_CompileCommand_getDirectory(cx_command));
|
std::string directory =
|
||||||
std::string relative_filename = clang::ToString(clang_CompileCommand_getFilename(cx_command));
|
clang::ToString(clang_CompileCommand_getDirectory(cx_command));
|
||||||
|
std::string relative_filename =
|
||||||
|
clang::ToString(clang_CompileCommand_getFilename(cx_command));
|
||||||
std::string absolute_filename = directory + "/" + relative_filename;
|
std::string absolute_filename = directory + "/" + relative_filename;
|
||||||
|
|
||||||
CompileCommandsEntry entry;
|
CompileCommandsEntry entry;
|
||||||
@ -305,9 +284,11 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(
|
|||||||
unsigned num_args = clang_CompileCommand_getNumArgs(cx_command);
|
unsigned num_args = clang_CompileCommand_getNumArgs(cx_command);
|
||||||
entry.args.reserve(num_args);
|
entry.args.reserve(num_args);
|
||||||
for (unsigned j = 0; j < num_args; ++j)
|
for (unsigned j = 0; j < num_args; ++j)
|
||||||
entry.args.push_back(clang::ToString(clang_CompileCommand_getArg(cx_command, j)));
|
entry.args.push_back(
|
||||||
|
clang::ToString(clang_CompileCommand_getArg(cx_command, j)));
|
||||||
|
|
||||||
result.push_back(GetCompilationEntryFromCompileCommandEntry(quote_includes, angle_includes, extra_flags, entry));
|
result.push_back(GetCompilationEntryFromCompileCommandEntry(
|
||||||
|
quote_includes, angle_includes, extra_flags, entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
clang_CompileCommands_dispose(cx_commands);
|
clang_CompileCommands_dispose(cx_commands);
|
||||||
@ -356,14 +337,18 @@ int ComputeGuessScore(const std::string& a, const std::string& b) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Project::Load(const std::vector<std::string>& extra_flags, const std::string& directory) {
|
void Project::Load(const std::vector<std::string>& extra_flags,
|
||||||
|
const std::string& directory) {
|
||||||
std::unordered_set<std::string> unique_quote_includes;
|
std::unordered_set<std::string> unique_quote_includes;
|
||||||
std::unordered_set<std::string> unique_angle_includes;
|
std::unordered_set<std::string> unique_angle_includes;
|
||||||
|
|
||||||
entries = LoadCompilationEntriesFromDirectory(unique_quote_includes, unique_angle_includes, extra_flags, directory);
|
entries = LoadCompilationEntriesFromDirectory(
|
||||||
|
unique_quote_includes, unique_angle_includes, extra_flags, directory);
|
||||||
|
|
||||||
quote_include_directories.assign(unique_quote_includes.begin(), unique_quote_includes.end());
|
quote_include_directories.assign(unique_quote_includes.begin(),
|
||||||
angle_include_directories.assign(unique_angle_includes.begin(), unique_angle_includes.end());
|
unique_quote_includes.end());
|
||||||
|
angle_include_directories.assign(unique_angle_includes.begin(),
|
||||||
|
unique_angle_includes.end());
|
||||||
|
|
||||||
for (std::string& path : quote_include_directories) {
|
for (std::string& path : quote_include_directories) {
|
||||||
EnsureEndsInSlash(path);
|
EnsureEndsInSlash(path);
|
||||||
@ -379,7 +364,8 @@ void Project::Load(const std::vector<std::string>& extra_flags, const std::strin
|
|||||||
absolute_path_to_entry_index_[entries[i].filename] = i;
|
absolute_path_to_entry_index_[entries[i].filename] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
Project::Entry Project::FindCompilationEntryForFile(const std::string& filename) {
|
Project::Entry Project::FindCompilationEntryForFile(
|
||||||
|
const std::string& filename) {
|
||||||
auto it = absolute_path_to_entry_index_.find(filename);
|
auto it = absolute_path_to_entry_index_.find(filename);
|
||||||
if (it != absolute_path_to_entry_index_.end())
|
if (it != absolute_path_to_entry_index_.end())
|
||||||
return entries[it->second];
|
return entries[it->second];
|
||||||
@ -404,7 +390,9 @@ Project::Entry Project::FindCompilationEntryForFile(const std::string& filename)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::ForAllFilteredFiles(Config* config, std::function<void(int i, const Entry& entry)> action) {
|
void Project::ForAllFilteredFiles(
|
||||||
|
Config* config,
|
||||||
|
std::function<void(int i, const Entry& entry)> action) {
|
||||||
GroupMatch matcher(config->indexWhitelist, config->indexBlacklist);
|
GroupMatch matcher(config->indexWhitelist, config->indexBlacklist);
|
||||||
for (int i = 0; i < entries.size(); ++i) {
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
const Project::Entry& entry = entries[i];
|
const Project::Entry& entry = entries[i];
|
||||||
@ -413,7 +401,8 @@ void Project::ForAllFilteredFiles(Config* config, std::function<void(int i, cons
|
|||||||
action(i, entries[i]);
|
action(i, entries[i]);
|
||||||
else {
|
else {
|
||||||
if (config->logSkippedPathsForIndex) {
|
if (config->logSkippedPathsForIndex) {
|
||||||
LOG_S(INFO) << "[" << i + 1 << "/" << entries.size() << "]: Failed " << failure_reason << "; skipping " << entry.filename;
|
LOG_S(INFO) << "[" << i + 1 << "/" << entries.size() << "]: Failed "
|
||||||
|
<< failure_reason << "; skipping " << entry.filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,36 +414,39 @@ TEST_CASE("Entry inference") {
|
|||||||
Project p;
|
Project p;
|
||||||
{
|
{
|
||||||
Project::Entry e;
|
Project::Entry e;
|
||||||
e.args = { "arg1" };
|
e.args = {"arg1"};
|
||||||
e.filename = "/a/b/c/d/bar.cc";
|
e.filename = "/a/b/c/d/bar.cc";
|
||||||
p.entries.push_back(e);
|
p.entries.push_back(e);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Project::Entry e;
|
Project::Entry e;
|
||||||
e.args = { "arg2" };
|
e.args = {"arg2"};
|
||||||
e.filename = "/a/b/c/baz.cc";
|
e.filename = "/a/b/c/baz.cc";
|
||||||
p.entries.push_back(e);
|
p.entries.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guess at same directory level, when there are parent directories.
|
// Guess at same directory level, when there are parent directories.
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("/a/b/c/d/new.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("/a/b/c/d/new.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg1" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg1"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guess at same directory level, when there are child directories.
|
// Guess at same directory level, when there are child directories.
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("/a/b/c/new.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("/a/b/c/new.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg2" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg2"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guess at new directory (use the closest parent directory).
|
// Guess at new directory (use the closest parent directory).
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("/a/b/c/new/new.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("/a/b/c/new/new.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg2" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg2"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,51 +454,55 @@ TEST_CASE("Entry inference prefers same file endings") {
|
|||||||
Project p;
|
Project p;
|
||||||
{
|
{
|
||||||
Project::Entry e;
|
Project::Entry e;
|
||||||
e.args = { "arg1" };
|
e.args = {"arg1"};
|
||||||
e.filename = "common/simple_browsertest.cc";
|
e.filename = "common/simple_browsertest.cc";
|
||||||
p.entries.push_back(e);
|
p.entries.push_back(e);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Project::Entry e;
|
Project::Entry e;
|
||||||
e.args = { "arg2" };
|
e.args = {"arg2"};
|
||||||
e.filename = "common/simple_unittest.cc";
|
e.filename = "common/simple_unittest.cc";
|
||||||
p.entries.push_back(e);
|
p.entries.push_back(e);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Project::Entry e;
|
Project::Entry e;
|
||||||
e.args = { "arg3" };
|
e.args = {"arg3"};
|
||||||
e.filename = "common/a/simple_unittest.cc";
|
e.filename = "common/a/simple_unittest.cc";
|
||||||
p.entries.push_back(e);
|
p.entries.push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Prefer files with the same ending.
|
// Prefer files with the same ending.
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("my_browsertest.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("my_browsertest.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg1" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg1"});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("my_unittest.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("my_unittest.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg2" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg2"});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("common/my_browsertest.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("common/my_browsertest.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg1" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg1"});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("common/my_unittest.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("common/my_unittest.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg2" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg2"});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefer the same directory over matching file-ending.
|
// Prefer the same directory over matching file-ending.
|
||||||
{
|
{
|
||||||
optional<Project::Entry> entry = p.FindCompilationEntryForFile("common/a/foo.cc");
|
optional<Project::Entry> entry =
|
||||||
|
p.FindCompilationEntryForFile("common/a/foo.cc");
|
||||||
REQUIRE(entry.has_value());
|
REQUIRE(entry.has_value());
|
||||||
REQUIRE(entry->args == std::vector<std::string>{ "arg3" });
|
REQUIRE(entry->args == std::vector<std::string>{"arg3"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
struct Project {
|
struct Project {
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@ -35,12 +35,14 @@ struct Project {
|
|||||||
// discover all files and args. Otherwise, a recursive directory listing of
|
// discover all files and args. Otherwise, a recursive directory listing of
|
||||||
// all *.cpp, *.cc, *.h, and *.hpp files will be used. clang arguments can be
|
// all *.cpp, *.cc, *.h, and *.hpp files will be used. clang arguments can be
|
||||||
// specified in a clang_args file located inside of |directory|.
|
// specified in a clang_args file located inside of |directory|.
|
||||||
void Load(const std::vector<std::string>& extra_flags, const std::string& directory);
|
void Load(const std::vector<std::string>& extra_flags,
|
||||||
|
const std::string& directory);
|
||||||
|
|
||||||
// Lookup the CompilationEntry for |filename|. If no entry was found this
|
// Lookup the CompilationEntry for |filename|. If no entry was found this
|
||||||
// will infer one based on existing project structure.
|
// will infer one based on existing project structure.
|
||||||
Entry FindCompilationEntryForFile(const std::string& filename);
|
Entry FindCompilationEntryForFile(const std::string& filename);
|
||||||
|
|
||||||
void ForAllFilteredFiles(Config* config, std::function<void(int i, const Entry& entry)> action);
|
void ForAllFilteredFiles(
|
||||||
|
Config* config,
|
||||||
|
std::function<void(int i, const Entry& entry)> action);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
600
src/query.cc
600
src/query.cc
@ -2,24 +2,26 @@
|
|||||||
|
|
||||||
#include "indexer.h"
|
#include "indexer.h"
|
||||||
|
|
||||||
#include <optional.h>
|
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
#include <optional.h>
|
||||||
#include <loguru.hpp>
|
#include <loguru.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <unordered_set>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
||||||
// TODO: Make all copy constructors explicit.
|
// TODO: Make all copy constructors explicit.
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
optional<QueryType::DefUpdate> ToQuery(const IdMap& id_map, const IndexType::Def& type) {
|
optional<QueryType::DefUpdate> ToQuery(const IdMap& id_map,
|
||||||
|
const IndexType::Def& type) {
|
||||||
if (type.detailed_name.empty())
|
if (type.detailed_name.empty())
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
@ -36,7 +38,8 @@ optional<QueryType::DefUpdate> ToQuery(const IdMap& id_map, const IndexType::Def
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryFunc::DefUpdate> ToQuery(const IdMap& id_map, const IndexFunc::Def& func) {
|
optional<QueryFunc::DefUpdate> ToQuery(const IdMap& id_map,
|
||||||
|
const IndexFunc::Def& func) {
|
||||||
if (func.detailed_name.empty())
|
if (func.detailed_name.empty())
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
@ -52,7 +55,8 @@ optional<QueryFunc::DefUpdate> ToQuery(const IdMap& id_map, const IndexFunc::Def
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryVar::DefUpdate> ToQuery(const IdMap& id_map, const IndexVar::Def& var) {
|
optional<QueryVar::DefUpdate> ToQuery(const IdMap& id_map,
|
||||||
|
const IndexVar::Def& var) {
|
||||||
if (var.detailed_name.empty())
|
if (var.detailed_name.empty())
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
@ -69,15 +73,13 @@ optional<QueryVar::DefUpdate> ToQuery(const IdMap& id_map, const IndexVar::Def&
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Adds the mergeable updates in |source| to |dest|. If a mergeable update for
|
// Adds the mergeable updates in |source| to |dest|. If a mergeable update for
|
||||||
// the destination type already exists, it will be combined. This makes merging
|
// the destination type already exists, it will be combined. This makes merging
|
||||||
// updates take longer but reduces import time on the querydb thread.
|
// updates take longer but reduces import time on the querydb thread.
|
||||||
template <typename TId, typename TValue>
|
template <typename TId, typename TValue>
|
||||||
void AddMergeableRange(
|
void AddMergeableRange(
|
||||||
std::vector<MergeableUpdate<TId, TValue>>* dest,
|
std::vector<MergeableUpdate<TId, TValue>>* dest,
|
||||||
const std::vector<MergeableUpdate<TId, TValue>>& source) {
|
const std::vector<MergeableUpdate<TId, TValue>>& source) {
|
||||||
|
|
||||||
// TODO: Consider caching the lookup table. It can probably save even more
|
// TODO: Consider caching the lookup table. It can probably save even more
|
||||||
// time at the cost of some additional memory.
|
// time at the cost of some additional memory.
|
||||||
|
|
||||||
@ -93,8 +95,7 @@ void AddMergeableRange(
|
|||||||
if (it != id_to_index.end()) {
|
if (it != id_to_index.end()) {
|
||||||
AddRange(&(*dest)[it->second].to_add, entry.to_add);
|
AddRange(&(*dest)[it->second].to_add, entry.to_add);
|
||||||
AddRange(&(*dest)[it->second].to_remove, entry.to_remove);
|
AddRange(&(*dest)[it->second].to_remove, entry.to_remove);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dest->push_back(entry);
|
dest->push_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,34 +106,31 @@ void AddMergeableRange(
|
|||||||
// that are in |current| but not |previous| to |added|.
|
// that are in |current| but not |previous| to |added|.
|
||||||
//
|
//
|
||||||
// Returns true iff |removed| or |added| are non-empty.
|
// Returns true iff |removed| or |added| are non-empty.
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool ComputeDifferenceForUpdate(
|
bool ComputeDifferenceForUpdate(std::vector<T>& previous,
|
||||||
std::vector<T>& previous, std::vector<T>& current,
|
std::vector<T>& current,
|
||||||
std::vector<T>* removed, std::vector<T>* added) {
|
std::vector<T>* removed,
|
||||||
|
std::vector<T>* added) {
|
||||||
// We need to sort to use std::set_difference.
|
// We need to sort to use std::set_difference.
|
||||||
std::sort(previous.begin(), previous.end());
|
std::sort(previous.begin(), previous.end());
|
||||||
std::sort(current.begin(), current.end());
|
std::sort(current.begin(), current.end());
|
||||||
|
|
||||||
// Returns the elements in |previous| that are not in |current|.
|
// Returns the elements in |previous| that are not in |current|.
|
||||||
std::set_difference(
|
std::set_difference(previous.begin(), previous.end(), current.begin(),
|
||||||
previous.begin(), previous.end(),
|
current.end(), std::back_inserter(*removed));
|
||||||
current.begin(), current.end(),
|
|
||||||
std::back_inserter(*removed));
|
|
||||||
// Returns the elements in |current| that are not in |previous|.
|
// Returns the elements in |current| that are not in |previous|.
|
||||||
std::set_difference(
|
std::set_difference(current.begin(), current.end(), previous.begin(),
|
||||||
current.begin(), current.end(),
|
previous.end(), std::back_inserter(*added));
|
||||||
previous.begin(), previous.end(),
|
|
||||||
std::back_inserter(*added));
|
|
||||||
|
|
||||||
return !removed->empty() || !added->empty();
|
return !removed->empty() || !added->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void CompareGroups(
|
void CompareGroups(std::vector<T>& previous_data,
|
||||||
std::vector<T>& previous_data, std::vector<T>& current_data,
|
std::vector<T>& current_data,
|
||||||
std::function<void(T*)> on_removed, std::function<void(T*)> on_added, std::function<void(T*, T*)> on_found) {
|
std::function<void(T*)> on_removed,
|
||||||
|
std::function<void(T*)> on_added,
|
||||||
|
std::function<void(T*, T*)> on_found) {
|
||||||
std::sort(previous_data.begin(), previous_data.end());
|
std::sort(previous_data.begin(), previous_data.end());
|
||||||
std::sort(current_data.begin(), current_data.end());
|
std::sort(current_data.begin(), current_data.end());
|
||||||
|
|
||||||
@ -186,7 +184,8 @@ QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexFile& indexed) {
|
|||||||
|
|
||||||
for (const IndexType& type : indexed.types) {
|
for (const IndexType& type : indexed.types) {
|
||||||
if (type.def.definition_spelling.has_value())
|
if (type.def.definition_spelling.has_value())
|
||||||
add_all_symbols(id_map.ToSymbol(type.id), type.def.definition_spelling.value());
|
add_all_symbols(id_map.ToSymbol(type.id),
|
||||||
|
type.def.definition_spelling.value());
|
||||||
if (type.def.definition_extent.has_value())
|
if (type.def.definition_extent.has_value())
|
||||||
add_outline(id_map.ToSymbol(type.id), type.def.definition_extent.value());
|
add_outline(id_map.ToSymbol(type.id), type.def.definition_extent.value());
|
||||||
for (const Range& use : type.uses)
|
for (const Range& use : type.uses)
|
||||||
@ -194,7 +193,8 @@ QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexFile& indexed) {
|
|||||||
}
|
}
|
||||||
for (const IndexFunc& func : indexed.funcs) {
|
for (const IndexFunc& func : indexed.funcs) {
|
||||||
if (func.def.definition_spelling.has_value())
|
if (func.def.definition_spelling.has_value())
|
||||||
add_all_symbols(id_map.ToSymbol(func.id), func.def.definition_spelling.value());
|
add_all_symbols(id_map.ToSymbol(func.id),
|
||||||
|
func.def.definition_spelling.value());
|
||||||
if (func.def.definition_extent.has_value())
|
if (func.def.definition_extent.has_value())
|
||||||
add_outline(id_map.ToSymbol(func.id), func.def.definition_extent.value());
|
add_outline(id_map.ToSymbol(func.id), func.def.definition_extent.value());
|
||||||
for (const IndexFunc::Declaration& decl : func.declarations) {
|
for (const IndexFunc::Declaration& decl : func.declarations) {
|
||||||
@ -203,63 +203,37 @@ QueryFile::Def BuildFileDef(const IdMap& id_map, const IndexFile& indexed) {
|
|||||||
add_outline(id_map.ToSymbol(func.id), decl.spelling);
|
add_outline(id_map.ToSymbol(func.id), decl.spelling);
|
||||||
}
|
}
|
||||||
for (const IndexFuncRef& caller : func.callers) {
|
for (const IndexFuncRef& caller : func.callers) {
|
||||||
if (caller.is_implicit) continue;
|
if (caller.is_implicit)
|
||||||
|
continue;
|
||||||
add_all_symbols(id_map.ToSymbol(func.id), caller.loc);
|
add_all_symbols(id_map.ToSymbol(func.id), caller.loc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const IndexVar& var : indexed.vars) {
|
for (const IndexVar& var : indexed.vars) {
|
||||||
if (var.def.definition_spelling.has_value())
|
if (var.def.definition_spelling.has_value())
|
||||||
add_all_symbols(id_map.ToSymbol(var.id), var.def.definition_spelling.value());
|
add_all_symbols(id_map.ToSymbol(var.id),
|
||||||
|
var.def.definition_spelling.value());
|
||||||
if (var.def.definition_extent.has_value())
|
if (var.def.definition_extent.has_value())
|
||||||
add_outline(id_map.ToSymbol(var.id), var.def.definition_extent.value());
|
add_outline(id_map.ToSymbol(var.id), var.def.definition_extent.value());
|
||||||
for (const Range& use : var.uses)
|
for (const Range& use : var.uses)
|
||||||
add_all_symbols(id_map.ToSymbol(var.id), use);
|
add_all_symbols(id_map.ToSymbol(var.id), use);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(def.outline.begin(), def.outline.end(), [](const SymbolRef& a, const SymbolRef& b) {
|
std::sort(def.outline.begin(), def.outline.end(),
|
||||||
return a.loc.range.start < b.loc.range.start;
|
[](const SymbolRef& a, const SymbolRef& b) {
|
||||||
});
|
return a.loc.range.start < b.loc.range.start;
|
||||||
std::sort(def.all_symbols.begin(), def.all_symbols.end(), [](const SymbolRef& a, const SymbolRef& b) {
|
});
|
||||||
return a.loc.range.start < b.loc.range.start;
|
std::sort(def.all_symbols.begin(), def.all_symbols.end(),
|
||||||
});
|
[](const SymbolRef& a, const SymbolRef& b) {
|
||||||
|
return a.loc.range.start < b.loc.range.start;
|
||||||
|
});
|
||||||
|
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
QueryFileId GetQueryFileIdFromPath(QueryDatabase* query_db,
|
||||||
|
const std::string& path) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QueryFileId GetQueryFileIdFromPath(QueryDatabase* query_db, const std::string& path) {
|
|
||||||
auto it = query_db->usr_to_file.find(LowerPathIfCaseInsensitive(path));
|
auto it = query_db->usr_to_file.find(LowerPathIfCaseInsensitive(path));
|
||||||
if (it != query_db->usr_to_file.end())
|
if (it != query_db->usr_to_file.end())
|
||||||
return QueryFileId(it->second.id);
|
return QueryFileId(it->second.id);
|
||||||
@ -304,17 +278,19 @@ QueryVarId GetQueryVarIdFromUsr(QueryDatabase* query_db, const Usr& usr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IdMap::IdMap(QueryDatabase* query_db, const IdCache& local_ids)
|
IdMap::IdMap(QueryDatabase* query_db, const IdCache& local_ids)
|
||||||
: local_ids(local_ids) {
|
: local_ids(local_ids) {
|
||||||
//LOG_S(INFO) << "Creating IdMap for " << local_ids.primary_file;
|
// LOG_S(INFO) << "Creating IdMap for " << local_ids.primary_file;
|
||||||
primary_file = GetQueryFileIdFromPath(query_db, local_ids.primary_file);
|
primary_file = GetQueryFileIdFromPath(query_db, local_ids.primary_file);
|
||||||
|
|
||||||
cached_type_ids_.resize(local_ids.type_id_to_usr.size());
|
cached_type_ids_.resize(local_ids.type_id_to_usr.size());
|
||||||
for (const auto& entry : local_ids.type_id_to_usr)
|
for (const auto& entry : local_ids.type_id_to_usr)
|
||||||
cached_type_ids_[entry.first] = GetQueryTypeIdFromUsr(query_db, entry.second);
|
cached_type_ids_[entry.first] =
|
||||||
|
GetQueryTypeIdFromUsr(query_db, entry.second);
|
||||||
|
|
||||||
cached_func_ids_.resize(local_ids.func_id_to_usr.size());
|
cached_func_ids_.resize(local_ids.func_id_to_usr.size());
|
||||||
for (const auto& entry : local_ids.func_id_to_usr)
|
for (const auto& entry : local_ids.func_id_to_usr)
|
||||||
cached_func_ids_[entry.first] = GetQueryFuncIdFromUsr(query_db, entry.second);
|
cached_func_ids_[entry.first] =
|
||||||
|
GetQueryFuncIdFromUsr(query_db, entry.second);
|
||||||
|
|
||||||
cached_var_ids_.resize(local_ids.var_id_to_usr.size());
|
cached_var_ids_.resize(local_ids.var_id_to_usr.size());
|
||||||
for (const auto& entry : local_ids.var_id_to_usr)
|
for (const auto& entry : local_ids.var_id_to_usr)
|
||||||
@ -329,7 +305,8 @@ QueryTypeId IdMap::ToQuery(IndexTypeId id) const {
|
|||||||
return QueryTypeId(cached_type_ids_.find(id)->second);
|
return QueryTypeId(cached_type_ids_.find(id)->second);
|
||||||
}
|
}
|
||||||
QueryFuncId IdMap::ToQuery(IndexFuncId id) const {
|
QueryFuncId IdMap::ToQuery(IndexFuncId id) const {
|
||||||
if (id.id == -1) return QueryFuncId((size_t)-1);
|
if (id.id == -1)
|
||||||
|
return QueryFuncId((size_t)-1);
|
||||||
assert(cached_func_ids_.find(id) != cached_func_ids_.end());
|
assert(cached_func_ids_.find(id) != cached_func_ids_.end());
|
||||||
return QueryFuncId(cached_func_ids_.find(id)->second);
|
return QueryFuncId(cached_func_ids_.find(id)->second);
|
||||||
}
|
}
|
||||||
@ -370,14 +347,16 @@ optional<QueryFuncRef> IdMap::ToQuery(optional<IndexFuncRef> ref) const {
|
|||||||
return nullopt;
|
return nullopt;
|
||||||
return ToQuery(ref.value());
|
return ToQuery(ref.value());
|
||||||
}
|
}
|
||||||
optional<QueryLocation> IdMap::ToQuery(optional<IndexFunc::Declaration> decl) const {
|
optional<QueryLocation> IdMap::ToQuery(
|
||||||
|
optional<IndexFunc::Declaration> decl) const {
|
||||||
if (!decl)
|
if (!decl)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
return ToQuery(decl.value());
|
return ToQuery(decl.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename In, typename Out>
|
template <typename In, typename Out>
|
||||||
std::vector<Out> ToQueryTransform(const IdMap& id_map, const std::vector<In>& input) {
|
std::vector<Out> ToQueryTransform(const IdMap& id_map,
|
||||||
|
const std::vector<In>& input) {
|
||||||
std::vector<Out> result;
|
std::vector<Out> result;
|
||||||
result.reserve(input.size());
|
result.reserve(input.size());
|
||||||
for (const In& in : input)
|
for (const In& in : input)
|
||||||
@ -399,7 +378,8 @@ std::vector<QueryVarId> IdMap::ToQuery(std::vector<IndexVarId> ids) const {
|
|||||||
std::vector<QueryFuncRef> IdMap::ToQuery(std::vector<IndexFuncRef> refs) const {
|
std::vector<QueryFuncRef> IdMap::ToQuery(std::vector<IndexFuncRef> refs) const {
|
||||||
return ToQueryTransform<IndexFuncRef, QueryFuncRef>(*this, refs);
|
return ToQueryTransform<IndexFuncRef, QueryFuncRef>(*this, refs);
|
||||||
}
|
}
|
||||||
std::vector<QueryLocation> IdMap::ToQuery(std::vector<IndexFunc::Declaration> decls) const {
|
std::vector<QueryLocation> IdMap::ToQuery(
|
||||||
|
std::vector<IndexFunc::Declaration> decls) const {
|
||||||
return ToQueryTransform<IndexFunc::Declaration, QueryLocation>(*this, decls);
|
return ToQueryTransform<IndexFunc::Declaration, QueryLocation>(*this, decls);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,33 +392,16 @@ SymbolIdx IdMap::ToSymbol(IndexFuncId id) const {
|
|||||||
SymbolIdx IdMap::ToSymbol(IndexVarId id) const {
|
SymbolIdx IdMap::ToSymbol(IndexVarId id) const {
|
||||||
return SymbolIdx(SymbolKind::Var, ToQuery(id).id);
|
return SymbolIdx(SymbolKind::Var, ToQuery(id).id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------
|
// ----------------------
|
||||||
// INDEX THREAD FUNCTIONS
|
// INDEX THREAD FUNCTIONS
|
||||||
// ----------------------
|
// ----------------------
|
||||||
|
|
||||||
// static
|
// static
|
||||||
IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map, const IdMap* current_id_map, IndexFile* previous, IndexFile* current) {
|
IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map,
|
||||||
|
const IdMap* current_id_map,
|
||||||
|
IndexFile* previous,
|
||||||
|
IndexFile* current) {
|
||||||
// This function runs on an indexer thread.
|
// This function runs on an indexer thread.
|
||||||
|
|
||||||
if (!previous_id_map) {
|
if (!previous_id_map) {
|
||||||
@ -449,25 +412,30 @@ IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map, const IdMap*
|
|||||||
return IndexUpdate(*previous_id_map, *current_id_map, *previous, *current);
|
return IndexUpdate(*previous_id_map, *current_id_map, *previous, *current);
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_map, IndexFile& previous_file, IndexFile& current_file) {
|
IndexUpdate::IndexUpdate(const IdMap& previous_id_map,
|
||||||
// This function runs on an indexer thread.
|
const IdMap& current_id_map,
|
||||||
|
IndexFile& previous_file,
|
||||||
|
IndexFile& current_file) {
|
||||||
|
// This function runs on an indexer thread.
|
||||||
|
|
||||||
// |query_name| is the name of the variable on the query type.
|
// |query_name| is the name of the variable on the query type.
|
||||||
// |index_name| is the name of the variable on the index type.
|
// |index_name| is the name of the variable on the index type.
|
||||||
// |type| is the type of the variable.
|
// |type| is the type of the variable.
|
||||||
#define PROCESS_UPDATE_DIFF(type_id, query_name, index_name, type) \
|
#define PROCESS_UPDATE_DIFF(type_id, query_name, index_name, type) \
|
||||||
{ \
|
{ \
|
||||||
/* Check for changes. */ \
|
/* Check for changes. */ \
|
||||||
std::vector<type> removed, added; \
|
std::vector<type> removed, added; \
|
||||||
auto previous = previous_id_map.ToQuery(previous_def->index_name); \
|
auto previous = previous_id_map.ToQuery(previous_def->index_name); \
|
||||||
auto current = current_id_map.ToQuery(current_def->index_name); \
|
auto current = current_id_map.ToQuery(current_def->index_name); \
|
||||||
bool did_add = ComputeDifferenceForUpdate( \
|
bool did_add = \
|
||||||
previous, current, \
|
ComputeDifferenceForUpdate(previous, current, &removed, &added); \
|
||||||
&removed, &added); \
|
if (did_add) { \
|
||||||
if (did_add) {\
|
/*std::cerr << "Adding mergeable update on " << \
|
||||||
/*std::cerr << "Adding mergeable update on " << current_def->def.short_name << " (" << current_def->def.usr << ") for field " << #index_name << std::endl;*/ \
|
* current_def->def.short_name << " (" << current_def->def.usr << ") for \
|
||||||
query_name.push_back(MergeableUpdate<type_id, type>(current_id_map.ToQuery(current_def->id), added, removed)); \
|
* field " << #index_name << std::endl;*/ \
|
||||||
} \
|
query_name.push_back(MergeableUpdate<type_id, type>( \
|
||||||
|
current_id_map.ToQuery(current_def->id), added, removed)); \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
// File
|
// File
|
||||||
files_def_update.push_back(BuildFileDef(current_id_map, current_file));
|
files_def_update.push_back(BuildFileDef(current_id_map, current_file));
|
||||||
@ -478,115 +446,171 @@ IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_m
|
|||||||
// away we don't want to remove the type/func/var usage.
|
// away we don't want to remove the type/func/var usage.
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
CompareGroups<IndexType>(previous_file.types, current_file.types,
|
CompareGroups<IndexType>(
|
||||||
/*onRemoved:*/[this, &previous_id_map](IndexType* type) {
|
previous_file.types, current_file.types,
|
||||||
if (type->def.definition_spelling)
|
/*onRemoved:*/
|
||||||
types_removed.push_back(type->def.usr);
|
[this, &previous_id_map](IndexType* type) {
|
||||||
else {
|
if (type->def.definition_spelling)
|
||||||
if (!type->derived.empty())
|
types_removed.push_back(type->def.usr);
|
||||||
types_derived.push_back(QueryType::DerivedUpdate(previous_id_map.ToQuery(type->id), {}, previous_id_map.ToQuery(type->derived)));
|
else {
|
||||||
if (!type->instances.empty())
|
if (!type->derived.empty())
|
||||||
types_instances.push_back(QueryType::InstancesUpdate(previous_id_map.ToQuery(type->id), {}, previous_id_map.ToQuery(type->instances)));
|
types_derived.push_back(QueryType::DerivedUpdate(
|
||||||
if (!type->uses.empty())
|
previous_id_map.ToQuery(type->id), {},
|
||||||
types_uses.push_back(QueryType::UsesUpdate(previous_id_map.ToQuery(type->id), {}, previous_id_map.ToQuery(type->uses)));
|
previous_id_map.ToQuery(type->derived)));
|
||||||
}
|
if (!type->instances.empty())
|
||||||
},
|
types_instances.push_back(QueryType::InstancesUpdate(
|
||||||
/*onAdded:*/[this, ¤t_id_map](IndexType* type) {
|
previous_id_map.ToQuery(type->id), {},
|
||||||
optional<QueryType::DefUpdate> def_update = ToQuery(current_id_map, type->def);
|
previous_id_map.ToQuery(type->instances)));
|
||||||
if (def_update)
|
if (!type->uses.empty())
|
||||||
types_def_update.push_back(*def_update);
|
types_uses.push_back(
|
||||||
if (!type->derived.empty())
|
QueryType::UsesUpdate(previous_id_map.ToQuery(type->id), {},
|
||||||
types_derived.push_back(QueryType::DerivedUpdate(current_id_map.ToQuery(type->id), current_id_map.ToQuery(type->derived)));
|
previous_id_map.ToQuery(type->uses)));
|
||||||
if (!type->instances.empty())
|
}
|
||||||
types_instances.push_back(QueryType::InstancesUpdate(current_id_map.ToQuery(type->id), current_id_map.ToQuery(type->instances)));
|
},
|
||||||
if (!type->uses.empty())
|
/*onAdded:*/
|
||||||
types_uses.push_back(QueryType::UsesUpdate(current_id_map.ToQuery(type->id), current_id_map.ToQuery(type->uses)));
|
[this, ¤t_id_map](IndexType* type) {
|
||||||
},
|
optional<QueryType::DefUpdate> def_update =
|
||||||
/*onFound:*/[this, &previous_id_map, ¤t_id_map](IndexType* previous_def, IndexType* current_def) {
|
ToQuery(current_id_map, type->def);
|
||||||
optional<QueryType::DefUpdate> previous_remapped_def = ToQuery(previous_id_map, previous_def->def);
|
if (def_update)
|
||||||
optional<QueryType::DefUpdate> current_remapped_def = ToQuery(current_id_map, current_def->def);
|
types_def_update.push_back(*def_update);
|
||||||
if (current_remapped_def && previous_remapped_def != current_remapped_def && !current_remapped_def->detailed_name.empty())
|
if (!type->derived.empty())
|
||||||
types_def_update.push_back(*current_remapped_def);
|
types_derived.push_back(
|
||||||
|
QueryType::DerivedUpdate(current_id_map.ToQuery(type->id),
|
||||||
|
current_id_map.ToQuery(type->derived)));
|
||||||
|
if (!type->instances.empty())
|
||||||
|
types_instances.push_back(QueryType::InstancesUpdate(
|
||||||
|
current_id_map.ToQuery(type->id),
|
||||||
|
current_id_map.ToQuery(type->instances)));
|
||||||
|
if (!type->uses.empty())
|
||||||
|
types_uses.push_back(
|
||||||
|
QueryType::UsesUpdate(current_id_map.ToQuery(type->id),
|
||||||
|
current_id_map.ToQuery(type->uses)));
|
||||||
|
},
|
||||||
|
/*onFound:*/
|
||||||
|
[this, &previous_id_map, ¤t_id_map](IndexType* previous_def,
|
||||||
|
IndexType* current_def) {
|
||||||
|
optional<QueryType::DefUpdate> previous_remapped_def =
|
||||||
|
ToQuery(previous_id_map, previous_def->def);
|
||||||
|
optional<QueryType::DefUpdate> current_remapped_def =
|
||||||
|
ToQuery(current_id_map, current_def->def);
|
||||||
|
if (current_remapped_def &&
|
||||||
|
previous_remapped_def != current_remapped_def &&
|
||||||
|
!current_remapped_def->detailed_name.empty())
|
||||||
|
types_def_update.push_back(*current_remapped_def);
|
||||||
|
|
||||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_derived, derived, QueryTypeId);
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_derived, derived, QueryTypeId);
|
||||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances, QueryVarId);
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_instances, instances,
|
||||||
PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, QueryLocation);
|
QueryVarId);
|
||||||
});
|
PROCESS_UPDATE_DIFF(QueryTypeId, types_uses, uses, QueryLocation);
|
||||||
|
});
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
CompareGroups<IndexFunc>(previous_file.funcs, current_file.funcs,
|
CompareGroups<IndexFunc>(
|
||||||
/*onRemoved:*/[this, &previous_id_map](IndexFunc* func) {
|
previous_file.funcs, current_file.funcs,
|
||||||
if (func->def.definition_spelling) {
|
/*onRemoved:*/
|
||||||
funcs_removed.push_back(func->def.usr);
|
[this, &previous_id_map](IndexFunc* func) {
|
||||||
}
|
if (func->def.definition_spelling) {
|
||||||
else {
|
funcs_removed.push_back(func->def.usr);
|
||||||
if (!func->declarations.empty())
|
} else {
|
||||||
funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(previous_id_map.ToQuery(func->id), {}, previous_id_map.ToQuery(func->declarations)));
|
if (!func->declarations.empty())
|
||||||
if (!func->derived.empty())
|
funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(
|
||||||
funcs_derived.push_back(QueryFunc::DerivedUpdate(previous_id_map.ToQuery(func->id), {}, previous_id_map.ToQuery(func->derived)));
|
previous_id_map.ToQuery(func->id), {},
|
||||||
if (!func->callers.empty())
|
previous_id_map.ToQuery(func->declarations)));
|
||||||
funcs_callers.push_back(QueryFunc::CallersUpdate(previous_id_map.ToQuery(func->id), {}, previous_id_map.ToQuery(func->callers)));
|
if (!func->derived.empty())
|
||||||
}
|
funcs_derived.push_back(QueryFunc::DerivedUpdate(
|
||||||
},
|
previous_id_map.ToQuery(func->id), {},
|
||||||
/*onAdded:*/[this, ¤t_id_map](IndexFunc* func) {
|
previous_id_map.ToQuery(func->derived)));
|
||||||
optional<QueryFunc::DefUpdate> def_update = ToQuery(current_id_map, func->def);
|
if (!func->callers.empty())
|
||||||
if (def_update)
|
funcs_callers.push_back(QueryFunc::CallersUpdate(
|
||||||
funcs_def_update.push_back(*def_update);
|
previous_id_map.ToQuery(func->id), {},
|
||||||
if (!func->declarations.empty())
|
previous_id_map.ToQuery(func->callers)));
|
||||||
funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(current_id_map.ToQuery(func->id), current_id_map.ToQuery(func->declarations)));
|
}
|
||||||
if (!func->derived.empty())
|
},
|
||||||
funcs_derived.push_back(QueryFunc::DerivedUpdate(current_id_map.ToQuery(func->id), current_id_map.ToQuery(func->derived)));
|
/*onAdded:*/
|
||||||
if (!func->callers.empty())
|
[this, ¤t_id_map](IndexFunc* func) {
|
||||||
funcs_callers.push_back(QueryFunc::CallersUpdate(current_id_map.ToQuery(func->id), current_id_map.ToQuery(func->callers)));
|
optional<QueryFunc::DefUpdate> def_update =
|
||||||
},
|
ToQuery(current_id_map, func->def);
|
||||||
/*onFound:*/[this, &previous_id_map, ¤t_id_map](IndexFunc* previous_def, IndexFunc* current_def) {
|
if (def_update)
|
||||||
optional<QueryFunc::DefUpdate> previous_remapped_def = ToQuery(previous_id_map, previous_def->def);
|
funcs_def_update.push_back(*def_update);
|
||||||
optional<QueryFunc::DefUpdate> current_remapped_def = ToQuery(current_id_map, current_def->def);
|
if (!func->declarations.empty())
|
||||||
if (current_remapped_def && previous_remapped_def != current_remapped_def && !current_remapped_def->detailed_name.empty())
|
funcs_declarations.push_back(QueryFunc::DeclarationsUpdate(
|
||||||
funcs_def_update.push_back(*current_remapped_def);
|
current_id_map.ToQuery(func->id),
|
||||||
|
current_id_map.ToQuery(func->declarations)));
|
||||||
|
if (!func->derived.empty())
|
||||||
|
funcs_derived.push_back(
|
||||||
|
QueryFunc::DerivedUpdate(current_id_map.ToQuery(func->id),
|
||||||
|
current_id_map.ToQuery(func->derived)));
|
||||||
|
if (!func->callers.empty())
|
||||||
|
funcs_callers.push_back(
|
||||||
|
QueryFunc::CallersUpdate(current_id_map.ToQuery(func->id),
|
||||||
|
current_id_map.ToQuery(func->callers)));
|
||||||
|
},
|
||||||
|
/*onFound:*/
|
||||||
|
[this, &previous_id_map, ¤t_id_map](IndexFunc* previous_def,
|
||||||
|
IndexFunc* current_def) {
|
||||||
|
optional<QueryFunc::DefUpdate> previous_remapped_def =
|
||||||
|
ToQuery(previous_id_map, previous_def->def);
|
||||||
|
optional<QueryFunc::DefUpdate> current_remapped_def =
|
||||||
|
ToQuery(current_id_map, current_def->def);
|
||||||
|
if (current_remapped_def &&
|
||||||
|
previous_remapped_def != current_remapped_def &&
|
||||||
|
!current_remapped_def->detailed_name.empty())
|
||||||
|
funcs_def_update.push_back(*current_remapped_def);
|
||||||
|
|
||||||
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_declarations, declarations, QueryLocation);
|
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_declarations, declarations,
|
||||||
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_derived, derived, QueryFuncId);
|
QueryLocation);
|
||||||
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_callers, callers, QueryFuncRef);
|
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_derived, derived, QueryFuncId);
|
||||||
});
|
PROCESS_UPDATE_DIFF(QueryFuncId, funcs_callers, callers, QueryFuncRef);
|
||||||
|
});
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
CompareGroups<IndexVar>(previous_file.vars, current_file.vars,
|
CompareGroups<IndexVar>(
|
||||||
/*onRemoved:*/[this, &previous_id_map](IndexVar* var) {
|
previous_file.vars, current_file.vars,
|
||||||
if (var->def.definition_spelling) {
|
/*onRemoved:*/
|
||||||
vars_removed.push_back(var->def.usr);
|
[this, &previous_id_map](IndexVar* var) {
|
||||||
}
|
if (var->def.definition_spelling) {
|
||||||
else {
|
vars_removed.push_back(var->def.usr);
|
||||||
if (!var->uses.empty())
|
} else {
|
||||||
vars_uses.push_back(QueryVar::UsesUpdate(previous_id_map.ToQuery(var->id), {}, previous_id_map.ToQuery(var->uses)));
|
if (!var->uses.empty())
|
||||||
}
|
vars_uses.push_back(
|
||||||
},
|
QueryVar::UsesUpdate(previous_id_map.ToQuery(var->id), {},
|
||||||
/*onAdded:*/[this, ¤t_id_map](IndexVar* var) {
|
previous_id_map.ToQuery(var->uses)));
|
||||||
optional<QueryVar::DefUpdate> def_update = ToQuery(current_id_map, var->def);
|
}
|
||||||
if (def_update)
|
},
|
||||||
vars_def_update.push_back(*def_update);
|
/*onAdded:*/
|
||||||
if (!var->uses.empty())
|
[this, ¤t_id_map](IndexVar* var) {
|
||||||
vars_uses.push_back(QueryVar::UsesUpdate(current_id_map.ToQuery(var->id), current_id_map.ToQuery(var->uses)));
|
optional<QueryVar::DefUpdate> def_update =
|
||||||
},
|
ToQuery(current_id_map, var->def);
|
||||||
/*onFound:*/[this, &previous_id_map, ¤t_id_map](IndexVar* previous_def, IndexVar* current_def) {
|
if (def_update)
|
||||||
optional<QueryVar::DefUpdate> previous_remapped_def = ToQuery(previous_id_map, previous_def->def);
|
vars_def_update.push_back(*def_update);
|
||||||
optional<QueryVar::DefUpdate> current_remapped_def = ToQuery(current_id_map, current_def->def);
|
if (!var->uses.empty())
|
||||||
if (current_remapped_def && previous_remapped_def != current_remapped_def && !current_remapped_def->detailed_name.empty())
|
vars_uses.push_back(
|
||||||
vars_def_update.push_back(*current_remapped_def);
|
QueryVar::UsesUpdate(current_id_map.ToQuery(var->id),
|
||||||
|
current_id_map.ToQuery(var->uses)));
|
||||||
|
},
|
||||||
|
/*onFound:*/
|
||||||
|
[this, &previous_id_map, ¤t_id_map](IndexVar* previous_def,
|
||||||
|
IndexVar* current_def) {
|
||||||
|
optional<QueryVar::DefUpdate> previous_remapped_def =
|
||||||
|
ToQuery(previous_id_map, previous_def->def);
|
||||||
|
optional<QueryVar::DefUpdate> current_remapped_def =
|
||||||
|
ToQuery(current_id_map, current_def->def);
|
||||||
|
if (current_remapped_def &&
|
||||||
|
previous_remapped_def != current_remapped_def &&
|
||||||
|
!current_remapped_def->detailed_name.empty())
|
||||||
|
vars_def_update.push_back(*current_remapped_def);
|
||||||
|
|
||||||
PROCESS_UPDATE_DIFF(QueryVarId, vars_uses, uses, QueryLocation);
|
PROCESS_UPDATE_DIFF(QueryVarId, vars_uses, uses, QueryLocation);
|
||||||
});
|
});
|
||||||
|
|
||||||
#undef PROCESS_UPDATE_DIFF
|
#undef PROCESS_UPDATE_DIFF
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexUpdate::Merge(const IndexUpdate& update) {
|
void IndexUpdate::Merge(const IndexUpdate& update) {
|
||||||
// This function runs on an indexer thread.
|
// This function runs on an indexer thread.
|
||||||
|
|
||||||
#define INDEX_UPDATE_APPEND(name) \
|
#define INDEX_UPDATE_APPEND(name) AddRange(&name, update.name);
|
||||||
AddRange(&name, update.name);
|
#define INDEX_UPDATE_MERGE(name) AddMergeableRange(&name, update.name);
|
||||||
#define INDEX_UPDATE_MERGE(name) \
|
|
||||||
AddMergeableRange(&name, update.name);
|
|
||||||
|
|
||||||
INDEX_UPDATE_APPEND(files_removed);
|
INDEX_UPDATE_APPEND(files_removed);
|
||||||
INDEX_UPDATE_APPEND(files_def_update);
|
INDEX_UPDATE_APPEND(files_def_update);
|
||||||
@ -619,37 +643,12 @@ std::string IndexUpdate::ToString() {
|
|||||||
return output.GetString();
|
return output.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// QUERYDB THREAD FUNCTIONS
|
// QUERYDB THREAD FUNCTIONS
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
void QueryDatabase::RemoveUsrs(SymbolKind usr_kind, const std::vector<Usr>& to_remove) {
|
void QueryDatabase::RemoveUsrs(SymbolKind usr_kind,
|
||||||
|
const std::vector<Usr>& to_remove) {
|
||||||
// This function runs on the querydb thread.
|
// This function runs on the querydb thread.
|
||||||
|
|
||||||
// When we remove an element, we just erase the state from the storage. We do
|
// When we remove an element, we just erase the state from the storage. We do
|
||||||
@ -690,20 +689,20 @@ void QueryDatabase::RemoveUsrs(SymbolKind usr_kind, const std::vector<Usr>& to_r
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
|
void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
|
||||||
// This function runs on the querydb thread.
|
// This function runs on the querydb thread.
|
||||||
|
|
||||||
// Example types:
|
// Example types:
|
||||||
// storage_name => std::vector<optional<QueryType>>
|
// storage_name => std::vector<optional<QueryType>>
|
||||||
// merge_update => QueryType::DerivedUpdate => MergeableUpdate<QueryTypeId, QueryTypeId>
|
// merge_update => QueryType::DerivedUpdate =>
|
||||||
// def => QueryType
|
// MergeableUpdate<QueryTypeId, QueryTypeId> def => QueryType
|
||||||
// def->def_var_name => std::vector<QueryTypeId>
|
// def->def_var_name => std::vector<QueryTypeId>
|
||||||
#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
|
#define HANDLE_MERGEABLE(update_var_name, def_var_name, storage_name) \
|
||||||
for (auto merge_update : update->update_var_name) { \
|
for (auto merge_update : update->update_var_name) { \
|
||||||
auto& def = storage_name[merge_update.id.id]; \
|
auto& def = storage_name[merge_update.id.id]; \
|
||||||
if (!def) \
|
if (!def) \
|
||||||
continue; /* TODO: Should we continue or create an empty def? */ \
|
continue; /* TODO: Should we continue or create an empty def? */ \
|
||||||
AddRange(&def->def_var_name, merge_update.to_add); \
|
AddRange(&def->def_var_name, merge_update.to_add); \
|
||||||
RemoveRange(&def->def_var_name, merge_update.to_remove); \
|
RemoveRange(&def->def_var_name, merge_update.to_remove); \
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveUsrs(SymbolKind::File, update->files_removed);
|
RemoveUsrs(SymbolKind::File, update->files_removed);
|
||||||
@ -728,7 +727,8 @@ void QueryDatabase::ApplyIndexUpdate(IndexUpdate* update) {
|
|||||||
#undef HANDLE_MERGEABLE
|
#undef HANDLE_MERGEABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::ImportOrUpdate(const std::vector<QueryFile::DefUpdate>& updates) {
|
void QueryDatabase::ImportOrUpdate(
|
||||||
|
const std::vector<QueryFile::DefUpdate>& updates) {
|
||||||
// This function runs on the querydb thread.
|
// This function runs on the querydb thread.
|
||||||
|
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
@ -740,11 +740,13 @@ void QueryDatabase::ImportOrUpdate(const std::vector<QueryFile::DefUpdate>& upda
|
|||||||
existing = QueryFile(def.path);
|
existing = QueryFile(def.path);
|
||||||
|
|
||||||
existing->def = def;
|
existing->def = def;
|
||||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::File, it->second.id, def.path);
|
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::File,
|
||||||
|
it->second.id, def.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::ImportOrUpdate(const std::vector<QueryType::DefUpdate>& updates) {
|
void QueryDatabase::ImportOrUpdate(
|
||||||
|
const std::vector<QueryType::DefUpdate>& updates) {
|
||||||
// This function runs on the querydb thread.
|
// This function runs on the querydb thread.
|
||||||
|
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
@ -763,11 +765,13 @@ void QueryDatabase::ImportOrUpdate(const std::vector<QueryType::DefUpdate>& upda
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
existing->def = def;
|
existing->def = def;
|
||||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Type, it->second.id, def.detailed_name);
|
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Type,
|
||||||
|
it->second.id, def.detailed_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::ImportOrUpdate(const std::vector<QueryFunc::DefUpdate>& updates) {
|
void QueryDatabase::ImportOrUpdate(
|
||||||
|
const std::vector<QueryFunc::DefUpdate>& updates) {
|
||||||
// This function runs on the querydb thread.
|
// This function runs on the querydb thread.
|
||||||
|
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
@ -786,11 +790,13 @@ void QueryDatabase::ImportOrUpdate(const std::vector<QueryFunc::DefUpdate>& upda
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
existing->def = def;
|
existing->def = def;
|
||||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Func, it->second.id, def.detailed_name);
|
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Func,
|
||||||
|
it->second.id, def.detailed_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::ImportOrUpdate(const std::vector<QueryVar::DefUpdate>& updates) {
|
void QueryDatabase::ImportOrUpdate(
|
||||||
|
const std::vector<QueryVar::DefUpdate>& updates) {
|
||||||
// This function runs on the querydb thread.
|
// This function runs on the querydb thread.
|
||||||
|
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
@ -810,17 +816,20 @@ void QueryDatabase::ImportOrUpdate(const std::vector<QueryVar::DefUpdate>& updat
|
|||||||
|
|
||||||
existing->def = def;
|
existing->def = def;
|
||||||
if (!def.is_local)
|
if (!def.is_local)
|
||||||
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Var, it->second.id, def.detailed_name);
|
UpdateDetailedNames(&existing->detailed_name_idx, SymbolKind::Var,
|
||||||
|
it->second.id, def.detailed_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryDatabase::UpdateDetailedNames(size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name) {
|
void QueryDatabase::UpdateDetailedNames(size_t* qualified_name_index,
|
||||||
|
SymbolKind kind,
|
||||||
|
size_t symbol_index,
|
||||||
|
const std::string& name) {
|
||||||
if (*qualified_name_index == -1) {
|
if (*qualified_name_index == -1) {
|
||||||
detailed_names.push_back(name);
|
detailed_names.push_back(name);
|
||||||
symbols.push_back(SymbolIdx(kind, symbol_index));
|
symbols.push_back(SymbolIdx(kind, symbol_index));
|
||||||
*qualified_name_index = detailed_names.size() - 1;
|
*qualified_name_index = detailed_names.size() - 1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
detailed_names[*qualified_name_index] = name;
|
detailed_names[*qualified_name_index] = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -831,31 +840,39 @@ IndexUpdate GetDelta(IndexFile previous, IndexFile current) {
|
|||||||
QueryDatabase db;
|
QueryDatabase db;
|
||||||
IdMap previous_map(&db, previous.id_cache);
|
IdMap previous_map(&db, previous.id_cache);
|
||||||
IdMap current_map(&db, current.id_cache);
|
IdMap current_map(&db, current.id_cache);
|
||||||
return IndexUpdate::CreateDelta(&previous_map, ¤t_map, &previous, ¤t);
|
return IndexUpdate::CreateDelta(&previous_map, ¤t_map, &previous,
|
||||||
|
¤t);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("remove defs") {
|
TEST_CASE("remove defs") {
|
||||||
IndexFile previous("foo.cc");
|
IndexFile previous("foo.cc");
|
||||||
IndexFile current("foo.cc");
|
IndexFile current("foo.cc");
|
||||||
|
|
||||||
previous.Resolve(previous.ToTypeId("usr1"))->def.definition_spelling = Range(Position(1, 0));
|
previous.Resolve(previous.ToTypeId("usr1"))->def.definition_spelling =
|
||||||
previous.Resolve(previous.ToFuncId("usr2"))->def.definition_spelling = Range(Position(2, 0));
|
Range(Position(1, 0));
|
||||||
previous.Resolve(previous.ToVarId("usr3"))->def.definition_spelling = Range(Position(3, 0));
|
previous.Resolve(previous.ToFuncId("usr2"))->def.definition_spelling =
|
||||||
|
Range(Position(2, 0));
|
||||||
|
previous.Resolve(previous.ToVarId("usr3"))->def.definition_spelling =
|
||||||
|
Range(Position(3, 0));
|
||||||
|
|
||||||
IndexUpdate update = GetDelta(previous, current);
|
IndexUpdate update = GetDelta(previous, current);
|
||||||
|
|
||||||
REQUIRE(update.types_removed == std::vector<Usr>{ "usr1" });
|
REQUIRE(update.types_removed == std::vector<Usr>{"usr1"});
|
||||||
REQUIRE(update.funcs_removed == std::vector<Usr>{ "usr2" });
|
REQUIRE(update.funcs_removed == std::vector<Usr>{"usr2"});
|
||||||
REQUIRE(update.vars_removed == std::vector<Usr>{ "usr3" });
|
REQUIRE(update.vars_removed == std::vector<Usr>{"usr3"});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("do not remove ref-only defs") {
|
TEST_CASE("do not remove ref-only defs") {
|
||||||
IndexFile previous("foo.cc");
|
IndexFile previous("foo.cc");
|
||||||
IndexFile current("foo.cc");
|
IndexFile current("foo.cc");
|
||||||
|
|
||||||
previous.Resolve(previous.ToTypeId("usr1"))->uses.push_back(Range(Position(1, 0)));
|
previous.Resolve(previous.ToTypeId("usr1"))
|
||||||
previous.Resolve(previous.ToFuncId("usr2"))->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)), false /*is_implicit*/));
|
->uses.push_back(Range(Position(1, 0)));
|
||||||
previous.Resolve(previous.ToVarId("usr3"))->uses.push_back(Range(Position(3, 0)));
|
previous.Resolve(previous.ToFuncId("usr2"))
|
||||||
|
->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)),
|
||||||
|
false /*is_implicit*/));
|
||||||
|
previous.Resolve(previous.ToVarId("usr3"))
|
||||||
|
->uses.push_back(Range(Position(3, 0)));
|
||||||
|
|
||||||
IndexUpdate update = GetDelta(previous, current);
|
IndexUpdate update = GetDelta(previous, current);
|
||||||
|
|
||||||
@ -871,8 +888,10 @@ TEST_CASE("func callers") {
|
|||||||
IndexFunc* pf = previous.Resolve(previous.ToFuncId("usr"));
|
IndexFunc* pf = previous.Resolve(previous.ToFuncId("usr"));
|
||||||
IndexFunc* cf = current.Resolve(current.ToFuncId("usr"));
|
IndexFunc* cf = current.Resolve(current.ToFuncId("usr"));
|
||||||
|
|
||||||
pf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(1, 0)), false /*is_implicit*/));
|
pf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(1, 0)),
|
||||||
cf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)), false /*is_implicit*/));
|
false /*is_implicit*/));
|
||||||
|
cf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)),
|
||||||
|
false /*is_implicit*/));
|
||||||
|
|
||||||
IndexUpdate update = GetDelta(previous, current);
|
IndexUpdate update = GetDelta(previous, current);
|
||||||
|
|
||||||
@ -880,7 +899,8 @@ TEST_CASE("func callers") {
|
|||||||
REQUIRE(update.funcs_callers.size() == 1);
|
REQUIRE(update.funcs_callers.size() == 1);
|
||||||
REQUIRE(update.funcs_callers[0].id == QueryFuncId(0));
|
REQUIRE(update.funcs_callers[0].id == QueryFuncId(0));
|
||||||
REQUIRE(update.funcs_callers[0].to_remove.size() == 1);
|
REQUIRE(update.funcs_callers[0].to_remove.size() == 1);
|
||||||
REQUIRE(update.funcs_callers[0].to_remove[0].loc.range == Range(Position(1, 0)));
|
REQUIRE(update.funcs_callers[0].to_remove[0].loc.range ==
|
||||||
|
Range(Position(1, 0)));
|
||||||
REQUIRE(update.funcs_callers[0].to_add.size() == 1);
|
REQUIRE(update.funcs_callers[0].to_add.size() == 1);
|
||||||
REQUIRE(update.funcs_callers[0].to_add[0].loc.range == Range(Position(2, 0)));
|
REQUIRE(update.funcs_callers[0].to_add[0].loc.range == Range(Position(2, 0)));
|
||||||
}
|
}
|
||||||
@ -912,18 +932,24 @@ TEST_CASE("apply delta") {
|
|||||||
|
|
||||||
IndexFunc* pf = previous.Resolve(previous.ToFuncId("usr"));
|
IndexFunc* pf = previous.Resolve(previous.ToFuncId("usr"));
|
||||||
IndexFunc* cf = current.Resolve(current.ToFuncId("usr"));
|
IndexFunc* cf = current.Resolve(current.ToFuncId("usr"));
|
||||||
pf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(1, 0)), false /*is_implicit*/));
|
pf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(1, 0)),
|
||||||
pf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)), false /*is_implicit*/));
|
false /*is_implicit*/));
|
||||||
cf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(4, 0)), false /*is_implicit*/));
|
pf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(2, 0)),
|
||||||
cf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(5, 0)), false /*is_implicit*/));
|
false /*is_implicit*/));
|
||||||
|
cf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(4, 0)),
|
||||||
|
false /*is_implicit*/));
|
||||||
|
cf->callers.push_back(IndexFuncRef(IndexFuncId(0), Range(Position(5, 0)),
|
||||||
|
false /*is_implicit*/));
|
||||||
|
|
||||||
QueryDatabase db;
|
QueryDatabase db;
|
||||||
IdMap previous_map(&db, previous.id_cache);
|
IdMap previous_map(&db, previous.id_cache);
|
||||||
IdMap current_map(&db, current.id_cache);
|
IdMap current_map(&db, current.id_cache);
|
||||||
REQUIRE(db.funcs.size() == 1);
|
REQUIRE(db.funcs.size() == 1);
|
||||||
|
|
||||||
IndexUpdate import_update = IndexUpdate::CreateDelta(nullptr, &previous_map, nullptr, &previous);
|
IndexUpdate import_update =
|
||||||
IndexUpdate delta_update = IndexUpdate::CreateDelta(&previous_map, ¤t_map, &previous, ¤t);
|
IndexUpdate::CreateDelta(nullptr, &previous_map, nullptr, &previous);
|
||||||
|
IndexUpdate delta_update = IndexUpdate::CreateDelta(
|
||||||
|
&previous_map, ¤t_map, &previous, ¤t);
|
||||||
|
|
||||||
db.ApplyIndexUpdate(&import_update);
|
db.ApplyIndexUpdate(&import_update);
|
||||||
REQUIRE(db.funcs[0]->callers.size() == 2);
|
REQUIRE(db.funcs[0]->callers.size() == 2);
|
||||||
|
106
src/query.h
106
src/query.h
@ -20,22 +20,14 @@ using QueryTypeId = Id<QueryType>;
|
|||||||
using QueryFuncId = Id<QueryFunc>;
|
using QueryFuncId = Id<QueryFunc>;
|
||||||
using QueryVarId = Id<QueryVar>;
|
using QueryVarId = Id<QueryVar>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct IdMap;
|
struct IdMap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct QueryLocation {
|
struct QueryLocation {
|
||||||
QueryFileId path;
|
QueryFileId path;
|
||||||
Range range;
|
Range range;
|
||||||
|
|
||||||
QueryLocation() {} // Do not use, needed for reflect.
|
QueryLocation() {} // Do not use, needed for reflect.
|
||||||
QueryLocation(QueryFileId path, Range range)
|
QueryLocation(QueryFileId path, Range range) : path(path), range(range) {}
|
||||||
: path(path), range(range) {}
|
|
||||||
|
|
||||||
QueryLocation OffsetStartColumn(int16_t offset) const {
|
QueryLocation OffsetStartColumn(int16_t offset) const {
|
||||||
QueryLocation result = *this;
|
QueryLocation result = *this;
|
||||||
@ -45,11 +37,11 @@ struct QueryLocation {
|
|||||||
|
|
||||||
bool operator==(const QueryLocation& other) const {
|
bool operator==(const QueryLocation& other) const {
|
||||||
// Note: We ignore |is_interesting|.
|
// Note: We ignore |is_interesting|.
|
||||||
return
|
return path == other.path && range == other.range;
|
||||||
path == other.path &&
|
}
|
||||||
range == other.range;
|
bool operator!=(const QueryLocation& other) const {
|
||||||
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
bool operator!=(const QueryLocation& other) const { return !(*this == other); }
|
|
||||||
bool operator<(const QueryLocation& o) const {
|
bool operator<(const QueryLocation& o) const {
|
||||||
if (path < o.path)
|
if (path < o.path)
|
||||||
return true;
|
return true;
|
||||||
@ -66,7 +58,9 @@ struct SymbolIdx {
|
|||||||
SymbolKind kind;
|
SymbolKind kind;
|
||||||
size_t idx;
|
size_t idx;
|
||||||
|
|
||||||
SymbolIdx() : kind(SymbolKind::Invalid), idx((size_t)-1) {} // Default ctor needed by stdlib. Do not use.
|
SymbolIdx()
|
||||||
|
: kind(SymbolKind::Invalid),
|
||||||
|
idx((size_t)-1) {} // Default ctor needed by stdlib. Do not use.
|
||||||
SymbolIdx(SymbolKind kind, uint64_t idx) : kind(kind), idx(idx) {}
|
SymbolIdx(SymbolKind kind, uint64_t idx) : kind(kind), idx(idx) {}
|
||||||
|
|
||||||
bool operator==(const SymbolIdx& that) const {
|
bool operator==(const SymbolIdx& that) const {
|
||||||
@ -85,7 +79,7 @@ struct SymbolRef {
|
|||||||
SymbolIdx idx;
|
SymbolIdx idx;
|
||||||
QueryLocation loc;
|
QueryLocation loc;
|
||||||
|
|
||||||
SymbolRef() {} // Do not use, needed for reflect.
|
SymbolRef() {} // Do not use, needed for reflect.
|
||||||
SymbolRef(SymbolIdx idx, QueryLocation loc) : idx(idx), loc(loc) {}
|
SymbolRef(SymbolIdx idx, QueryLocation loc) : idx(idx), loc(loc) {}
|
||||||
|
|
||||||
bool operator==(const SymbolRef& that) const {
|
bool operator==(const SymbolRef& that) const {
|
||||||
@ -108,11 +102,13 @@ struct QueryFuncRef {
|
|||||||
|
|
||||||
bool has_id() const { return id_.id != -1; }
|
bool has_id() const { return id_.id != -1; }
|
||||||
|
|
||||||
QueryFuncRef() {} // Do not use, needed for reflect.
|
QueryFuncRef() {} // Do not use, needed for reflect.
|
||||||
QueryFuncRef(QueryFuncId id, QueryLocation loc, bool is_implicit) : id_(id), loc(loc), is_implicit(is_implicit) {}
|
QueryFuncRef(QueryFuncId id, QueryLocation loc, bool is_implicit)
|
||||||
|
: id_(id), loc(loc), is_implicit(is_implicit) {}
|
||||||
|
|
||||||
bool operator==(const QueryFuncRef& that) const {
|
bool operator==(const QueryFuncRef& that) const {
|
||||||
return id_ == that.id_ && loc == that.loc && is_implicit == that.is_implicit;
|
return id_ == that.id_ && loc == that.loc &&
|
||||||
|
is_implicit == that.is_implicit;
|
||||||
}
|
}
|
||||||
bool operator!=(const QueryFuncRef& that) const { return !(*this == that); }
|
bool operator!=(const QueryFuncRef& that) const { return !(*this == that); }
|
||||||
bool operator<(const QueryFuncRef& that) const {
|
bool operator<(const QueryFuncRef& that) const {
|
||||||
@ -120,7 +116,8 @@ struct QueryFuncRef {
|
|||||||
return true;
|
return true;
|
||||||
if (id_ == that.id_ && loc.range.start < that.loc.range.start)
|
if (id_ == that.id_ && loc.range.start < that.loc.range.start)
|
||||||
return true;
|
return true;
|
||||||
return id_ == that.id_ && loc.range.start == that.loc.range.start && is_implicit < that.is_implicit;
|
return id_ == that.id_ && loc.range.start == that.loc.range.start &&
|
||||||
|
is_implicit < that.is_implicit;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(QueryFuncRef, id_, loc, is_implicit);
|
MAKE_REFLECT_STRUCT(QueryFuncRef, id_, loc, is_implicit);
|
||||||
@ -135,7 +132,7 @@ MAKE_REFLECT_STRUCT(QueryFuncRef, id_, loc, is_implicit);
|
|||||||
// that it can be merged with other updates before actually being applied to
|
// that it can be merged with other updates before actually being applied to
|
||||||
// the main database. See |MergeableUpdate|.
|
// the main database. See |MergeableUpdate|.
|
||||||
|
|
||||||
template<typename TId, typename TValue>
|
template <typename TId, typename TValue>
|
||||||
struct MergeableUpdate {
|
struct MergeableUpdate {
|
||||||
// The type/func/var which is getting new usages.
|
// The type/func/var which is getting new usages.
|
||||||
TId id;
|
TId id;
|
||||||
@ -144,11 +141,13 @@ struct MergeableUpdate {
|
|||||||
std::vector<TValue> to_remove;
|
std::vector<TValue> to_remove;
|
||||||
|
|
||||||
MergeableUpdate(TId id, const std::vector<TValue>& to_add)
|
MergeableUpdate(TId id, const std::vector<TValue>& to_add)
|
||||||
: id(id), to_add(to_add) {}
|
: id(id), to_add(to_add) {}
|
||||||
MergeableUpdate(TId id, const std::vector<TValue>& to_add, const std::vector<TValue>& to_remove)
|
MergeableUpdate(TId id,
|
||||||
: id(id), to_add(to_add), to_remove(to_remove) {}
|
const std::vector<TValue>& to_add,
|
||||||
|
const std::vector<TValue>& to_remove)
|
||||||
|
: id(id), to_add(to_add), to_remove(to_remove) {}
|
||||||
};
|
};
|
||||||
template<typename TVisitor, typename TId, typename TValue>
|
template <typename TVisitor, typename TId, typename TValue>
|
||||||
void Reflect(TVisitor& visitor, MergeableUpdate<TId, TValue>& value) {
|
void Reflect(TVisitor& visitor, MergeableUpdate<TId, TValue>& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER(id);
|
REFLECT_MEMBER(id);
|
||||||
@ -178,7 +177,10 @@ struct QueryFile {
|
|||||||
MAKE_REFLECT_STRUCT(QueryFile::Def, path, outline, all_symbols);
|
MAKE_REFLECT_STRUCT(QueryFile::Def, path, outline, all_symbols);
|
||||||
|
|
||||||
struct QueryType {
|
struct QueryType {
|
||||||
using DefUpdate = TypeDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryLocation>;
|
using DefUpdate = TypeDefDefinitionData<QueryTypeId,
|
||||||
|
QueryFuncId,
|
||||||
|
QueryVarId,
|
||||||
|
QueryLocation>;
|
||||||
using DerivedUpdate = MergeableUpdate<QueryTypeId, QueryTypeId>;
|
using DerivedUpdate = MergeableUpdate<QueryTypeId, QueryTypeId>;
|
||||||
using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>;
|
using InstancesUpdate = MergeableUpdate<QueryTypeId, QueryVarId>;
|
||||||
using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>;
|
using UsesUpdate = MergeableUpdate<QueryTypeId, QueryLocation>;
|
||||||
@ -193,7 +195,11 @@ struct QueryType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct QueryFunc {
|
struct QueryFunc {
|
||||||
using DefUpdate = FuncDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryFuncRef, QueryLocation>;
|
using DefUpdate = FuncDefDefinitionData<QueryTypeId,
|
||||||
|
QueryFuncId,
|
||||||
|
QueryVarId,
|
||||||
|
QueryFuncRef,
|
||||||
|
QueryLocation>;
|
||||||
using DeclarationsUpdate = MergeableUpdate<QueryFuncId, QueryLocation>;
|
using DeclarationsUpdate = MergeableUpdate<QueryFuncId, QueryLocation>;
|
||||||
using DerivedUpdate = MergeableUpdate<QueryFuncId, QueryFuncId>;
|
using DerivedUpdate = MergeableUpdate<QueryFuncId, QueryFuncId>;
|
||||||
using CallersUpdate = MergeableUpdate<QueryFuncId, QueryFuncRef>;
|
using CallersUpdate = MergeableUpdate<QueryFuncId, QueryFuncRef>;
|
||||||
@ -208,7 +214,8 @@ struct QueryFunc {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct QueryVar {
|
struct QueryVar {
|
||||||
using DefUpdate = VarDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryLocation>;
|
using DefUpdate =
|
||||||
|
VarDefDefinitionData<QueryTypeId, QueryFuncId, QueryVarId, QueryLocation>;
|
||||||
using UsesUpdate = MergeableUpdate<QueryVarId, QueryLocation>;
|
using UsesUpdate = MergeableUpdate<QueryVarId, QueryLocation>;
|
||||||
|
|
||||||
DefUpdate def;
|
DefUpdate def;
|
||||||
@ -221,7 +228,10 @@ struct QueryVar {
|
|||||||
struct IndexUpdate {
|
struct IndexUpdate {
|
||||||
// Creates a new IndexUpdate based on the delta from previous to current. If
|
// Creates a new IndexUpdate based on the delta from previous to current. If
|
||||||
// no delta computation should be done just pass null for previous.
|
// no delta computation should be done just pass null for previous.
|
||||||
static IndexUpdate CreateDelta(const IdMap* previous_id_map, const IdMap* current_id_map, IndexFile* previous, IndexFile* current);
|
static IndexUpdate CreateDelta(const IdMap* previous_id_map,
|
||||||
|
const IdMap* current_id_map,
|
||||||
|
IndexFile* previous,
|
||||||
|
IndexFile* current);
|
||||||
|
|
||||||
// Merge |update| into this update; this can reduce overhead / index update
|
// Merge |update| into this update; this can reduce overhead / index update
|
||||||
// work can be parallelized.
|
// work can be parallelized.
|
||||||
@ -257,13 +267,27 @@ struct IndexUpdate {
|
|||||||
// Creates an index update assuming that |previous| is already
|
// Creates an index update assuming that |previous| is already
|
||||||
// in the index, so only the delta between |previous| and |current|
|
// in the index, so only the delta between |previous| and |current|
|
||||||
// will be applied.
|
// will be applied.
|
||||||
IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_map, IndexFile& previous, IndexFile& current);
|
IndexUpdate(const IdMap& previous_id_map,
|
||||||
|
const IdMap& current_id_map,
|
||||||
|
IndexFile& previous,
|
||||||
|
IndexFile& current);
|
||||||
};
|
};
|
||||||
// NOTICE: We're not reflecting on files_removed or files_def_update, it is too much output when logging
|
// NOTICE: We're not reflecting on files_removed or files_def_update, it is too
|
||||||
|
// much output when logging
|
||||||
MAKE_REFLECT_STRUCT(IndexUpdate,
|
MAKE_REFLECT_STRUCT(IndexUpdate,
|
||||||
types_removed, types_def_update, types_derived, types_instances, types_uses,
|
types_removed,
|
||||||
funcs_removed, funcs_def_update, funcs_declarations, funcs_derived, funcs_callers,
|
types_def_update,
|
||||||
vars_removed, vars_def_update, vars_uses);
|
types_derived,
|
||||||
|
types_instances,
|
||||||
|
types_uses,
|
||||||
|
funcs_removed,
|
||||||
|
funcs_def_update,
|
||||||
|
funcs_declarations,
|
||||||
|
funcs_derived,
|
||||||
|
funcs_callers,
|
||||||
|
vars_removed,
|
||||||
|
vars_def_update,
|
||||||
|
vars_uses);
|
||||||
|
|
||||||
// The query database is heavily optimized for fast queries. It is stored
|
// The query database is heavily optimized for fast queries. It is stored
|
||||||
// in-memory.
|
// in-memory.
|
||||||
@ -295,12 +319,12 @@ struct QueryDatabase {
|
|||||||
void ImportOrUpdate(const std::vector<QueryType::DefUpdate>& updates);
|
void ImportOrUpdate(const std::vector<QueryType::DefUpdate>& updates);
|
||||||
void ImportOrUpdate(const std::vector<QueryFunc::DefUpdate>& updates);
|
void ImportOrUpdate(const std::vector<QueryFunc::DefUpdate>& updates);
|
||||||
void ImportOrUpdate(const std::vector<QueryVar::DefUpdate>& updates);
|
void ImportOrUpdate(const std::vector<QueryVar::DefUpdate>& updates);
|
||||||
void UpdateDetailedNames(size_t* qualified_name_index, SymbolKind kind, size_t symbol_index, const std::string& name);
|
void UpdateDetailedNames(size_t* qualified_name_index,
|
||||||
|
SymbolKind kind,
|
||||||
|
size_t symbol_index,
|
||||||
|
const std::string& name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct IdMap {
|
struct IdMap {
|
||||||
const IdCache& local_ids;
|
const IdCache& local_ids;
|
||||||
QueryFileId primary_file;
|
QueryFileId primary_file;
|
||||||
@ -324,12 +348,14 @@ struct IdMap {
|
|||||||
std::vector<QueryFuncId> ToQuery(std::vector<IndexFuncId> ids) const;
|
std::vector<QueryFuncId> ToQuery(std::vector<IndexFuncId> ids) const;
|
||||||
std::vector<QueryVarId> ToQuery(std::vector<IndexVarId> ids) const;
|
std::vector<QueryVarId> ToQuery(std::vector<IndexVarId> ids) const;
|
||||||
std::vector<QueryFuncRef> ToQuery(std::vector<IndexFuncRef> refs) const;
|
std::vector<QueryFuncRef> ToQuery(std::vector<IndexFuncRef> refs) const;
|
||||||
std::vector<QueryLocation> ToQuery(std::vector<IndexFunc::Declaration> decls) const;
|
std::vector<QueryLocation> ToQuery(
|
||||||
|
std::vector<IndexFunc::Declaration> decls) const;
|
||||||
|
|
||||||
SymbolIdx ToSymbol(IndexTypeId id) const;
|
SymbolIdx ToSymbol(IndexTypeId id) const;
|
||||||
SymbolIdx ToSymbol(IndexFuncId id) const;
|
SymbolIdx ToSymbol(IndexFuncId id) const;
|
||||||
SymbolIdx ToSymbol(IndexVarId id) const;
|
SymbolIdx ToSymbol(IndexVarId id) const;
|
||||||
private:
|
|
||||||
|
private:
|
||||||
spp::sparse_hash_map<IndexTypeId, QueryTypeId> cached_type_ids_;
|
spp::sparse_hash_map<IndexTypeId, QueryTypeId> cached_type_ids_;
|
||||||
spp::sparse_hash_map<IndexFuncId, QueryFuncId> cached_func_ids_;
|
spp::sparse_hash_map<IndexFuncId, QueryFuncId> cached_func_ids_;
|
||||||
spp::sparse_hash_map<IndexVarId, QueryVarId> cached_var_ids_;
|
spp::sparse_hash_map<IndexVarId, QueryVarId> cached_var_ids_;
|
||||||
|
@ -13,159 +13,170 @@ int ComputeRangeSize(const Range& range) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const QueryTypeId& id) {
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
|
const QueryTypeId& id) {
|
||||||
optional<QueryType>& type = db->types[id.id];
|
optional<QueryType>& type = db->types[id.id];
|
||||||
if (type)
|
if (type)
|
||||||
return type->def.definition_spelling;
|
return type->def.definition_spelling;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const QueryFuncId& id) {
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
|
const QueryFuncId& id) {
|
||||||
optional<QueryFunc>& func = db->funcs[id.id];
|
optional<QueryFunc>& func = db->funcs[id.id];
|
||||||
if (func)
|
if (func)
|
||||||
return func->def.definition_spelling;
|
return func->def.definition_spelling;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const QueryVarId& id) {
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
|
const QueryVarId& id) {
|
||||||
optional<QueryVar>& var = db->vars[id.id];
|
optional<QueryVar>& var = db->vars[id.id];
|
||||||
if (var)
|
if (var)
|
||||||
return var->def.definition_spelling;
|
return var->def.definition_spelling;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol) {
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
if (type)
|
if (type)
|
||||||
return type->def.definition_spelling;
|
return type->def.definition_spelling;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
if (func)
|
if (func)
|
||||||
return func->def.definition_spelling;
|
return func->def.definition_spelling;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
if (var)
|
if (var)
|
||||||
return var->def.definition_spelling;
|
return var->def.definition_spelling;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::File:
|
case SymbolKind::File:
|
||||||
case SymbolKind::Invalid: {
|
case SymbolKind::Invalid: {
|
||||||
assert(false && "unexpected");
|
assert(false && "unexpected");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol) {
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
if (type)
|
if (type)
|
||||||
return type->def.definition_extent;
|
return type->def.definition_extent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
if (func)
|
if (func)
|
||||||
return func->def.definition_extent;
|
return func->def.definition_extent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
if (var)
|
if (var)
|
||||||
return var->def.definition_extent;
|
return var->def.definition_extent;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::File: {
|
case SymbolKind::File: {
|
||||||
return QueryLocation(QueryFileId(symbol.idx), Range(Position(1, 1), Position(1, 1)));
|
return QueryLocation(QueryFileId(symbol.idx),
|
||||||
}
|
Range(Position(1, 1), Position(1, 1)));
|
||||||
case SymbolKind::Invalid: {
|
}
|
||||||
assert(false && "unexpected");
|
case SymbolKind::Invalid: {
|
||||||
break;
|
assert(false && "unexpected");
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
if (type)
|
if (type)
|
||||||
return type->def.detailed_name;
|
return type->def.detailed_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
if (func)
|
if (func)
|
||||||
return func->def.detailed_name;
|
return func->def.detailed_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
if (var)
|
if (var)
|
||||||
return var->def.detailed_name;
|
return var->def.detailed_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::File:
|
case SymbolKind::File:
|
||||||
case SymbolKind::Invalid: {
|
case SymbolKind::Invalid: {
|
||||||
assert(false && "unexpected");
|
assert(false && "unexpected");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol) {
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
if (type && type->def.definition_spelling)
|
if (type && type->def.definition_spelling)
|
||||||
return type->def.definition_spelling->path;
|
return type->def.definition_spelling->path;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
if (func) {
|
if (func) {
|
||||||
if (!func->declarations.empty())
|
if (!func->declarations.empty())
|
||||||
return func->declarations[0].path;
|
return func->declarations[0].path;
|
||||||
if (func->def.definition_spelling)
|
if (func->def.definition_spelling)
|
||||||
return func->def.definition_spelling->path;
|
return func->def.definition_spelling->path;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolKind::Var: {
|
||||||
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
|
if (var && var->def.definition_spelling)
|
||||||
|
return var->def.definition_spelling->path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolKind::File: {
|
||||||
|
return QueryFileId(symbol.idx);
|
||||||
|
}
|
||||||
|
case SymbolKind::Invalid: {
|
||||||
|
assert(false && "unexpected");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::Var: {
|
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
|
||||||
if (var && var->def.definition_spelling)
|
|
||||||
return var->def.definition_spelling->path;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::File: {
|
|
||||||
return QueryFileId(symbol.idx);
|
|
||||||
}
|
|
||||||
case SymbolKind::Invalid: {
|
|
||||||
assert(false && "unexpected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryFuncRef>& refs) {
|
std::vector<QueryLocation> ToQueryLocation(
|
||||||
|
QueryDatabase* db,
|
||||||
|
const std::vector<QueryFuncRef>& refs) {
|
||||||
std::vector<QueryLocation> locs;
|
std::vector<QueryLocation> locs;
|
||||||
locs.reserve(refs.size());
|
locs.reserve(refs.size());
|
||||||
for (const QueryFuncRef& ref : refs)
|
for (const QueryFuncRef& ref : refs)
|
||||||
locs.push_back(ref.loc);
|
locs.push_back(ref.loc);
|
||||||
return locs;
|
return locs;
|
||||||
}
|
}
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryTypeId>& ids) {
|
std::vector<QueryLocation> ToQueryLocation(
|
||||||
|
QueryDatabase* db,
|
||||||
|
const std::vector<QueryTypeId>& ids) {
|
||||||
std::vector<QueryLocation> locs;
|
std::vector<QueryLocation> locs;
|
||||||
locs.reserve(ids.size());
|
locs.reserve(ids.size());
|
||||||
for (const QueryTypeId& id : ids) {
|
for (const QueryTypeId& id : ids) {
|
||||||
@ -175,7 +186,9 @@ std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<
|
|||||||
}
|
}
|
||||||
return locs;
|
return locs;
|
||||||
}
|
}
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryFuncId>& ids) {
|
std::vector<QueryLocation> ToQueryLocation(
|
||||||
|
QueryDatabase* db,
|
||||||
|
const std::vector<QueryFuncId>& ids) {
|
||||||
std::vector<QueryLocation> locs;
|
std::vector<QueryLocation> locs;
|
||||||
locs.reserve(ids.size());
|
locs.reserve(ids.size());
|
||||||
for (const QueryFuncId& id : ids) {
|
for (const QueryFuncId& id : ids) {
|
||||||
@ -185,7 +198,8 @@ std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<
|
|||||||
}
|
}
|
||||||
return locs;
|
return locs;
|
||||||
}
|
}
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryVarId>& ids) {
|
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db,
|
||||||
|
const std::vector<QueryVarId>& ids) {
|
||||||
std::vector<QueryLocation> locs;
|
std::vector<QueryLocation> locs;
|
||||||
locs.reserve(ids.size());
|
locs.reserve(ids.size());
|
||||||
for (const QueryVarId& id : ids) {
|
for (const QueryVarId& id : ids) {
|
||||||
@ -196,81 +210,84 @@ std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<
|
|||||||
return locs;
|
return locs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol) {
|
||||||
std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db, const SymbolIdx& symbol) {
|
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
if (type)
|
if (type)
|
||||||
return type->uses;
|
return type->uses;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
// TODO: the vector allocation could be avoided.
|
// TODO: the vector allocation could be avoided.
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
if (func) {
|
if (func) {
|
||||||
std::vector<QueryLocation> result = ToQueryLocation(db, func->callers);
|
std::vector<QueryLocation> result = ToQueryLocation(db, func->callers);
|
||||||
AddRange(&result, func->declarations);
|
AddRange(&result, func->declarations);
|
||||||
if (func->def.definition_spelling)
|
if (func->def.definition_spelling)
|
||||||
result.push_back(*func->def.definition_spelling);
|
result.push_back(*func->def.definition_spelling);
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolKind::Var: {
|
||||||
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
|
if (var)
|
||||||
|
return var->uses;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SymbolKind::File:
|
||||||
|
case SymbolKind::Invalid: {
|
||||||
|
assert(false && "unexpected");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::Var: {
|
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
|
||||||
if (var)
|
|
||||||
return var->uses;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::File:
|
|
||||||
case SymbolKind::Invalid: {
|
|
||||||
assert(false && "unexpected");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(QueryDatabase* db, const SymbolIdx& symbol) {
|
std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(
|
||||||
|
QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol) {
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
// Returning the definition spelling of a type is a hack (and is why the
|
// Returning the definition spelling of a type is a hack (and is why the
|
||||||
// function has the postfix `ForGotoDefintion`, but it lets the user
|
// function has the postfix `ForGotoDefintion`, but it lets the user
|
||||||
// jump to the start of a type if clicking goto-definition on the same
|
// jump to the start of a type if clicking goto-definition on the same
|
||||||
// type from within the type definition.
|
// type from within the type definition.
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
if (type) {
|
if (type) {
|
||||||
optional<QueryLocation> declaration = type->def.definition_spelling;
|
optional<QueryLocation> declaration = type->def.definition_spelling;
|
||||||
if (declaration)
|
if (declaration)
|
||||||
return { *declaration };
|
return {*declaration};
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
case SymbolKind::Func: {
|
||||||
}
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
case SymbolKind::Func: {
|
if (func)
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
return func->declarations;
|
||||||
if (func)
|
break;
|
||||||
return func->declarations;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SymbolKind::Var: {
|
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
|
||||||
if (var) {
|
|
||||||
optional<QueryLocation> declaration = var->def.declaration;
|
|
||||||
if (declaration)
|
|
||||||
return { *declaration };
|
|
||||||
}
|
}
|
||||||
break;
|
case SymbolKind::Var: {
|
||||||
}
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
default:
|
if (var) {
|
||||||
break;
|
optional<QueryLocation> declaration = var->def.declaration;
|
||||||
|
if (declaration)
|
||||||
|
return {*declaration};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling(QueryDatabase* db, QueryFunc& func) {
|
optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling(
|
||||||
|
QueryDatabase* db,
|
||||||
|
QueryFunc& func) {
|
||||||
if (!func.def.base)
|
if (!func.def.base)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
optional<QueryFunc>& base = db->funcs[func.def.base->id];
|
optional<QueryFunc>& base = db->funcs[func.def.base->id];
|
||||||
@ -316,7 +333,8 @@ bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db, QueryFunc& root) {
|
std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db,
|
||||||
|
QueryFunc& root) {
|
||||||
std::vector<QueryFuncRef> callers;
|
std::vector<QueryFuncRef> callers;
|
||||||
|
|
||||||
optional<QueryFuncId> func_id = root.def.base;
|
optional<QueryFuncId> func_id = root.def.base;
|
||||||
@ -332,7 +350,8 @@ std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db, Query
|
|||||||
return callers;
|
return callers;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db, QueryFunc& root) {
|
std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db,
|
||||||
|
QueryFunc& root) {
|
||||||
std::vector<QueryFuncRef> callers;
|
std::vector<QueryFuncRef> callers;
|
||||||
|
|
||||||
std::queue<QueryFuncId> queue;
|
std::queue<QueryFuncId> queue;
|
||||||
@ -351,7 +370,8 @@ std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db, Qu
|
|||||||
return callers;
|
return callers;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<lsPosition> GetLsPosition(WorkingFile* working_file, const Position& position) {
|
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||||
|
const Position& position) {
|
||||||
if (!working_file)
|
if (!working_file)
|
||||||
return lsPosition(position.line - 1, position.column - 1);
|
return lsPosition(position.line - 1, position.column - 1);
|
||||||
|
|
||||||
@ -365,12 +385,14 @@ optional<lsPosition> GetLsPosition(WorkingFile* working_file, const Position& po
|
|||||||
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
||||||
if (!working_file) {
|
if (!working_file) {
|
||||||
return lsRange(
|
return lsRange(
|
||||||
lsPosition(location.start.line - 1, location.start.column - 1),
|
lsPosition(location.start.line - 1, location.start.column - 1),
|
||||||
lsPosition(location.end.line - 1, location.end.column - 1));
|
lsPosition(location.end.line - 1, location.end.column - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<int> start = working_file->GetBufferLineFromIndexLine(location.start.line);
|
optional<int> start =
|
||||||
optional<int> end = working_file->GetBufferLineFromIndexLine(location.end.line);
|
working_file->GetBufferLineFromIndexLine(location.start.line);
|
||||||
|
optional<int> end =
|
||||||
|
working_file->GetBufferLineFromIndexLine(location.end.line);
|
||||||
if (!start || !end)
|
if (!start || !end)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
@ -383,18 +405,18 @@ optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location) {
|
|||||||
if (*end < *start)
|
if (*end < *start)
|
||||||
*end = *start + (location.end.line - location.start.line);
|
*end = *start + (location.end.line - location.start.line);
|
||||||
|
|
||||||
return lsRange(
|
return lsRange(lsPosition(*start - 1, location.start.column - 1),
|
||||||
lsPosition(*start - 1, location.start.column - 1),
|
lsPosition(*end - 1, location.end.column - 1));
|
||||||
lsPosition(*end - 1, location.end.column - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id, std::string* path) {
|
lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
||||||
|
QueryFileId file_id,
|
||||||
|
std::string* path) {
|
||||||
optional<QueryFile>& file = db->files[file_id.id];
|
optional<QueryFile>& file = db->files[file_id.id];
|
||||||
if (file) {
|
if (file) {
|
||||||
*path = file->def.path;
|
*path = file->def.path;
|
||||||
return lsDocumentUri::FromPath(*path);
|
return lsDocumentUri::FromPath(*path);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
*path = "";
|
*path = "";
|
||||||
return lsDocumentUri::FromPath("");
|
return lsDocumentUri::FromPath("");
|
||||||
}
|
}
|
||||||
@ -404,25 +426,31 @@ lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id) {
|
|||||||
optional<QueryFile>& file = db->files[file_id.id];
|
optional<QueryFile>& file = db->files[file_id.id];
|
||||||
if (file) {
|
if (file) {
|
||||||
return lsDocumentUri::FromPath(file->def.path);
|
return lsDocumentUri::FromPath(file->def.path);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return lsDocumentUri::FromPath("");
|
return lsDocumentUri::FromPath("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<lsLocation> GetLsLocation(QueryDatabase* db, WorkingFiles* working_files, const QueryLocation& location) {
|
optional<lsLocation> GetLsLocation(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
const QueryLocation& location) {
|
||||||
std::string path;
|
std::string path;
|
||||||
lsDocumentUri uri = GetLsDocumentUri(db, location.path, &path);
|
lsDocumentUri uri = GetLsDocumentUri(db, location.path, &path);
|
||||||
optional<lsRange> range = GetLsRange(working_files->GetFileByFilename(path), location.range);
|
optional<lsRange> range =
|
||||||
|
GetLsRange(working_files->GetFileByFilename(path), location.range);
|
||||||
if (!range)
|
if (!range)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
return lsLocation(uri, *range);
|
return lsLocation(uri, *range);
|
||||||
}
|
}
|
||||||
|
|
||||||
NonElidedVector<lsLocation> GetLsLocations(QueryDatabase* db, WorkingFiles* working_files, const std::vector<QueryLocation>& locations) {
|
NonElidedVector<lsLocation> GetLsLocations(
|
||||||
|
QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
const std::vector<QueryLocation>& locations) {
|
||||||
std::unordered_set<lsLocation> unique_locations;
|
std::unordered_set<lsLocation> unique_locations;
|
||||||
for (const QueryLocation& query_location : locations) {
|
for (const QueryLocation& query_location : locations) {
|
||||||
optional<lsLocation> location = GetLsLocation(db, working_files, query_location);
|
optional<lsLocation> location =
|
||||||
|
GetLsLocation(db, working_files, query_location);
|
||||||
if (!location)
|
if (!location)
|
||||||
continue;
|
continue;
|
||||||
unique_locations.insert(*location);
|
unique_locations.insert(*location);
|
||||||
@ -435,75 +463,77 @@ NonElidedVector<lsLocation> GetLsLocations(QueryDatabase* db, WorkingFiles* work
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
||||||
optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db, WorkingFiles* working_files, SymbolIdx symbol) {
|
optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
SymbolIdx symbol) {
|
||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::File: {
|
case SymbolKind::File: {
|
||||||
optional<QueryFile>& file = db->files[symbol.idx];
|
optional<QueryFile>& file = db->files[symbol.idx];
|
||||||
if (!file)
|
if (!file)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
lsSymbolInformation info;
|
lsSymbolInformation info;
|
||||||
info.name = file->def.path;
|
info.name = file->def.path;
|
||||||
info.kind = lsSymbolKind::File;
|
info.kind = lsSymbolKind::File;
|
||||||
return info;
|
return info;
|
||||||
}
|
|
||||||
case SymbolKind::Type: {
|
|
||||||
optional<QueryType>& type = db->types[symbol.idx];
|
|
||||||
if (!type)
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
lsSymbolInformation info;
|
|
||||||
info.name = type->def.short_name;
|
|
||||||
if (type->def.detailed_name != type->def.short_name)
|
|
||||||
info.containerName = type->def.detailed_name;
|
|
||||||
info.kind = lsSymbolKind::Class;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
case SymbolKind::Func: {
|
|
||||||
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
|
||||||
if (!func)
|
|
||||||
return nullopt;
|
|
||||||
|
|
||||||
lsSymbolInformation info;
|
|
||||||
info.name = func->def.short_name;
|
|
||||||
info.containerName = func->def.detailed_name;
|
|
||||||
info.kind = lsSymbolKind::Function;
|
|
||||||
|
|
||||||
if (func->def.declaring_type.has_value()) {
|
|
||||||
optional<QueryType>& container = db->types[func->def.declaring_type->id];
|
|
||||||
if (container)
|
|
||||||
info.kind = lsSymbolKind::Method;
|
|
||||||
}
|
}
|
||||||
|
case SymbolKind::Type: {
|
||||||
|
optional<QueryType>& type = db->types[symbol.idx];
|
||||||
|
if (!type)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
return info;
|
lsSymbolInformation info;
|
||||||
}
|
info.name = type->def.short_name;
|
||||||
case SymbolKind::Var: {
|
if (type->def.detailed_name != type->def.short_name)
|
||||||
optional<QueryVar>& var = db->vars[symbol.idx];
|
info.containerName = type->def.detailed_name;
|
||||||
if (!var)
|
info.kind = lsSymbolKind::Class;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
case SymbolKind::Func: {
|
||||||
|
optional<QueryFunc>& func = db->funcs[symbol.idx];
|
||||||
|
if (!func)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
lsSymbolInformation info;
|
||||||
|
info.name = func->def.short_name;
|
||||||
|
info.containerName = func->def.detailed_name;
|
||||||
|
info.kind = lsSymbolKind::Function;
|
||||||
|
|
||||||
|
if (func->def.declaring_type.has_value()) {
|
||||||
|
optional<QueryType>& container =
|
||||||
|
db->types[func->def.declaring_type->id];
|
||||||
|
if (container)
|
||||||
|
info.kind = lsSymbolKind::Method;
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
case SymbolKind::Var: {
|
||||||
|
optional<QueryVar>& var = db->vars[symbol.idx];
|
||||||
|
if (!var)
|
||||||
|
return nullopt;
|
||||||
|
|
||||||
|
lsSymbolInformation info;
|
||||||
|
info.name += var->def.short_name;
|
||||||
|
info.containerName = var->def.detailed_name;
|
||||||
|
info.kind = lsSymbolKind::Variable;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
case SymbolKind::Invalid: {
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
}
|
||||||
lsSymbolInformation info;
|
|
||||||
info.name += var->def.short_name;
|
|
||||||
info.containerName = var->def.detailed_name;
|
|
||||||
info.kind = lsSymbolKind::Variable;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
case SymbolKind::Invalid: {
|
|
||||||
return nullopt;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddCodeLens(
|
void AddCodeLens(const char* singular,
|
||||||
const char* singular,
|
const char* plural,
|
||||||
const char* plural,
|
CommonCodeLensParams* common,
|
||||||
CommonCodeLensParams* common,
|
QueryLocation loc,
|
||||||
QueryLocation loc,
|
const std::vector<QueryLocation>& uses,
|
||||||
const std::vector<QueryLocation>& uses,
|
optional<QueryLocation> excluded,
|
||||||
optional<QueryLocation> excluded,
|
bool force_display) {
|
||||||
bool force_display) {
|
|
||||||
TCodeLens code_lens;
|
TCodeLens code_lens;
|
||||||
optional<lsRange> range = GetLsRange(common->working_file, loc.range);
|
optional<lsRange> range = GetLsRange(common->working_file, loc.range);
|
||||||
if (!range)
|
if (!range)
|
||||||
@ -519,13 +549,14 @@ void AddCodeLens(
|
|||||||
for (const QueryLocation& use : uses) {
|
for (const QueryLocation& use : uses) {
|
||||||
if (excluded == use)
|
if (excluded == use)
|
||||||
continue;
|
continue;
|
||||||
optional<lsLocation> location = GetLsLocation(common->db, common->working_files, use);
|
optional<lsLocation> location =
|
||||||
|
GetLsLocation(common->db, common->working_files, use);
|
||||||
if (!location)
|
if (!location)
|
||||||
continue;
|
continue;
|
||||||
unique_uses.insert(*location);
|
unique_uses.insert(*location);
|
||||||
}
|
}
|
||||||
code_lens.command->arguments.locations.assign(unique_uses.begin(),
|
code_lens.command->arguments.locations.assign(unique_uses.begin(),
|
||||||
unique_uses.end());
|
unique_uses.end());
|
||||||
|
|
||||||
// User visible label
|
// User visible label
|
||||||
size_t num_usages = unique_uses.size();
|
size_t num_usages = unique_uses.size();
|
||||||
@ -539,11 +570,15 @@ void AddCodeLens(
|
|||||||
common->result->push_back(code_lens);
|
common->result->push_back(code_lens);
|
||||||
}
|
}
|
||||||
|
|
||||||
lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db, WorkingFiles* working_files, const std::vector<QueryLocation>& locations, const std::string& new_text) {
|
lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
const std::vector<QueryLocation>& locations,
|
||||||
|
const std::string& new_text) {
|
||||||
std::unordered_map<QueryFileId, lsTextDocumentEdit> path_to_edit;
|
std::unordered_map<QueryFileId, lsTextDocumentEdit> path_to_edit;
|
||||||
|
|
||||||
for (auto& location : locations) {
|
for (auto& location : locations) {
|
||||||
optional<lsLocation> ls_location = GetLsLocation(db, working_files, location);
|
optional<lsLocation> ls_location =
|
||||||
|
GetLsLocation(db, working_files, location);
|
||||||
if (!ls_location)
|
if (!ls_location)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -555,11 +590,13 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db, WorkingFiles* working_file
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const std::string& path = file->def.path;
|
const std::string& path = file->def.path;
|
||||||
path_to_edit[location.path].textDocument.uri = lsDocumentUri::FromPath(path);
|
path_to_edit[location.path].textDocument.uri =
|
||||||
|
lsDocumentUri::FromPath(path);
|
||||||
|
|
||||||
WorkingFile* working_file = working_files->GetFileByFilename(path);
|
WorkingFile* working_file = working_files->GetFileByFilename(path);
|
||||||
if (working_file)
|
if (working_file)
|
||||||
path_to_edit[location.path].textDocument.version = working_file->version;
|
path_to_edit[location.path].textDocument.version =
|
||||||
|
working_file->version;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsTextEdit edit;
|
lsTextEdit edit;
|
||||||
@ -572,21 +609,23 @@ lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db, WorkingFiles* working_file
|
|||||||
edits.push_back(edit);
|
edits.push_back(edit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
lsWorkspaceEdit edit;
|
lsWorkspaceEdit edit;
|
||||||
for (const auto& changes : path_to_edit)
|
for (const auto& changes : path_to_edit)
|
||||||
edit.documentChanges.push_back(changes.second);
|
edit.documentChanges.push_back(changes.second);
|
||||||
return edit;
|
return edit;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file, QueryFile* file, lsPosition position) {
|
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||||
|
QueryFile* file,
|
||||||
|
lsPosition position) {
|
||||||
std::vector<SymbolRef> symbols;
|
std::vector<SymbolRef> symbols;
|
||||||
symbols.reserve(1);
|
symbols.reserve(1);
|
||||||
|
|
||||||
int target_line = position.line + 1;
|
int target_line = position.line + 1;
|
||||||
int target_column = position.character + 1;
|
int target_column = position.character + 1;
|
||||||
if (working_file) {
|
if (working_file) {
|
||||||
optional<int> index_line = working_file->GetIndexLineFromBufferLine(target_line);
|
optional<int> index_line =
|
||||||
|
working_file->GetIndexLineFromBufferLine(target_line);
|
||||||
if (index_line)
|
if (index_line)
|
||||||
target_line = *index_line;
|
target_line = *index_line;
|
||||||
}
|
}
|
||||||
@ -602,20 +641,25 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file, QueryFil
|
|||||||
//
|
//
|
||||||
// Order functions before other types, which makes goto definition work
|
// Order functions before other types, which makes goto definition work
|
||||||
// better on constructors.
|
// better on constructors.
|
||||||
std::sort(symbols.begin(), symbols.end(), [](const SymbolRef& a, const SymbolRef& b) {
|
std::sort(symbols.begin(), symbols.end(),
|
||||||
int a_size = ComputeRangeSize(a.loc.range);
|
[](const SymbolRef& a, const SymbolRef& b) {
|
||||||
int b_size = ComputeRangeSize(b.loc.range);
|
int a_size = ComputeRangeSize(a.loc.range);
|
||||||
|
int b_size = ComputeRangeSize(b.loc.range);
|
||||||
|
|
||||||
if (a_size == b_size)
|
if (a_size == b_size)
|
||||||
return a.idx.kind != b.idx.kind && a.idx.kind == SymbolKind::Func;
|
return a.idx.kind != b.idx.kind &&
|
||||||
|
a.idx.kind == SymbolKind::Func;
|
||||||
|
|
||||||
return a_size < b_size;
|
return a_size < b_size;
|
||||||
});
|
});
|
||||||
|
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHierarchyForType(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root) {
|
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
|
BuildParentInheritanceHierarchyForType(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryTypeId root) {
|
||||||
optional<QueryType>& root_type = db->types[root.id];
|
optional<QueryType>& root_type = db->types[root.id];
|
||||||
if (!root_type)
|
if (!root_type)
|
||||||
return {};
|
return {};
|
||||||
@ -631,8 +675,10 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHi
|
|||||||
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
|
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
|
||||||
parent_entry.name = parent_type->def.detailed_name;
|
parent_entry.name = parent_type->def.detailed_name;
|
||||||
if (parent_type->def.definition_spelling)
|
if (parent_type->def.definition_spelling)
|
||||||
parent_entry.location = GetLsLocation(db, working_files, *parent_type->def.definition_spelling);
|
parent_entry.location = GetLsLocation(
|
||||||
parent_entry.children = BuildParentInheritanceHierarchyForType(db, working_files, parent_id);
|
db, working_files, *parent_type->def.definition_spelling);
|
||||||
|
parent_entry.children =
|
||||||
|
BuildParentInheritanceHierarchyForType(db, working_files, parent_id);
|
||||||
|
|
||||||
parent_entries.push_back(parent_entry);
|
parent_entries.push_back(parent_entry);
|
||||||
}
|
}
|
||||||
@ -640,8 +686,10 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHi
|
|||||||
return parent_entries;
|
return parent_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForType(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root_id) {
|
BuildInheritanceHierarchyForType(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryTypeId root_id) {
|
||||||
optional<QueryType>& root_type = db->types[root_id.id];
|
optional<QueryType>& root_type = db->types[root_id.id];
|
||||||
if (!root_type)
|
if (!root_type)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
@ -651,7 +699,8 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForTyp
|
|||||||
// Name and location.
|
// Name and location.
|
||||||
entry.name = root_type->def.detailed_name;
|
entry.name = root_type->def.detailed_name;
|
||||||
if (root_type->def.definition_spelling)
|
if (root_type->def.definition_spelling)
|
||||||
entry.location = GetLsLocation(db, working_files, *root_type->def.definition_spelling);
|
entry.location =
|
||||||
|
GetLsLocation(db, working_files, *root_type->def.definition_spelling);
|
||||||
|
|
||||||
entry.children.reserve(root_type->derived.size());
|
entry.children.reserve(root_type->derived.size());
|
||||||
|
|
||||||
@ -659,13 +708,15 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForTyp
|
|||||||
Out_CqueryTypeHierarchyTree::TypeEntry base;
|
Out_CqueryTypeHierarchyTree::TypeEntry base;
|
||||||
base.name = "[[Base]]";
|
base.name = "[[Base]]";
|
||||||
base.location = entry.location;
|
base.location = entry.location;
|
||||||
base.children = BuildParentInheritanceHierarchyForType(db, working_files, root_id);
|
base.children =
|
||||||
|
BuildParentInheritanceHierarchyForType(db, working_files, root_id);
|
||||||
if (!base.children.empty())
|
if (!base.children.empty())
|
||||||
entry.children.push_back(base);
|
entry.children.push_back(base);
|
||||||
|
|
||||||
// Add derived.
|
// Add derived.
|
||||||
for (QueryTypeId derived : root_type->derived) {
|
for (QueryTypeId derived : root_type->derived) {
|
||||||
auto derived_entry = BuildInheritanceHierarchyForType(db, working_files, derived);
|
auto derived_entry =
|
||||||
|
BuildInheritanceHierarchyForType(db, working_files, derived);
|
||||||
if (derived_entry)
|
if (derived_entry)
|
||||||
entry.children.push_back(*derived_entry);
|
entry.children.push_back(*derived_entry);
|
||||||
}
|
}
|
||||||
@ -673,8 +724,10 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForTyp
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHierarchyForFunc(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root) {
|
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root) {
|
||||||
optional<QueryFunc>& root_func = db->funcs[root.id];
|
optional<QueryFunc>& root_func = db->funcs[root.id];
|
||||||
if (!root_func || !root_func->def.base)
|
if (!root_func || !root_func->def.base)
|
||||||
return {};
|
return {};
|
||||||
@ -686,16 +739,20 @@ NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHi
|
|||||||
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
|
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
|
||||||
parent_entry.name = parent_func->def.detailed_name;
|
parent_entry.name = parent_func->def.detailed_name;
|
||||||
if (parent_func->def.definition_spelling)
|
if (parent_func->def.definition_spelling)
|
||||||
parent_entry.location = GetLsLocation(db, working_files, *parent_func->def.definition_spelling);
|
parent_entry.location =
|
||||||
parent_entry.children = BuildParentInheritanceHierarchyForFunc(db, working_files, *root_func->def.base);
|
GetLsLocation(db, working_files, *parent_func->def.definition_spelling);
|
||||||
|
parent_entry.children = BuildParentInheritanceHierarchyForFunc(
|
||||||
|
db, working_files, *root_func->def.base);
|
||||||
|
|
||||||
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> entries;
|
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> entries;
|
||||||
entries.push_back(parent_entry);
|
entries.push_back(parent_entry);
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optional<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForFunc(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root_id) {
|
BuildInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root_id) {
|
||||||
optional<QueryFunc>& root_func = db->funcs[root_id.id];
|
optional<QueryFunc>& root_func = db->funcs[root_id.id];
|
||||||
if (!root_func)
|
if (!root_func)
|
||||||
return nullopt;
|
return nullopt;
|
||||||
@ -705,7 +762,8 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForFun
|
|||||||
// Name and location.
|
// Name and location.
|
||||||
entry.name = root_func->def.detailed_name;
|
entry.name = root_func->def.detailed_name;
|
||||||
if (root_func->def.definition_spelling)
|
if (root_func->def.definition_spelling)
|
||||||
entry.location = GetLsLocation(db, working_files, *root_func->def.definition_spelling);
|
entry.location =
|
||||||
|
GetLsLocation(db, working_files, *root_func->def.definition_spelling);
|
||||||
|
|
||||||
entry.children.reserve(root_func->derived.size());
|
entry.children.reserve(root_func->derived.size());
|
||||||
|
|
||||||
@ -713,13 +771,15 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForFun
|
|||||||
Out_CqueryTypeHierarchyTree::TypeEntry base;
|
Out_CqueryTypeHierarchyTree::TypeEntry base;
|
||||||
base.name = "[[Base]]";
|
base.name = "[[Base]]";
|
||||||
base.location = entry.location;
|
base.location = entry.location;
|
||||||
base.children = BuildParentInheritanceHierarchyForFunc(db, working_files, root_id);
|
base.children =
|
||||||
|
BuildParentInheritanceHierarchyForFunc(db, working_files, root_id);
|
||||||
if (!base.children.empty())
|
if (!base.children.empty())
|
||||||
entry.children.push_back(base);
|
entry.children.push_back(base);
|
||||||
|
|
||||||
// Add derived.
|
// Add derived.
|
||||||
for (QueryFuncId derived : root_func->derived) {
|
for (QueryFuncId derived : root_func->derived) {
|
||||||
auto derived_entry = BuildInheritanceHierarchyForFunc(db, working_files, derived);
|
auto derived_entry =
|
||||||
|
BuildInheritanceHierarchyForFunc(db, working_files, derived);
|
||||||
if (derived_entry)
|
if (derived_entry)
|
||||||
entry.children.push_back(*derived_entry);
|
entry.children.push_back(*derived_entry);
|
||||||
}
|
}
|
||||||
@ -727,13 +787,17 @@ optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForFun
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root) {
|
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(
|
||||||
|
QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root) {
|
||||||
optional<QueryFunc>& root_func = db->funcs[root.id];
|
optional<QueryFunc>& root_func = db->funcs[root.id];
|
||||||
if (!root_func)
|
if (!root_func)
|
||||||
return {};
|
return {};
|
||||||
if (!root_func->def.definition_spelling)
|
if (!root_func->def.definition_spelling)
|
||||||
return {};
|
return {};
|
||||||
optional<lsLocation> def_loc = GetLsLocation(db, working_files, *root_func->def.definition_spelling);
|
optional<lsLocation> def_loc =
|
||||||
|
GetLsLocation(db, working_files, *root_func->def.definition_spelling);
|
||||||
if (!def_loc)
|
if (!def_loc)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@ -747,12 +811,17 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(QueryDatabas
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root) {
|
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
||||||
|
QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root) {
|
||||||
optional<QueryFunc>& root_func = db->funcs[root.id];
|
optional<QueryFunc>& root_func = db->funcs[root.id];
|
||||||
if (!root_func)
|
if (!root_func)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto format_location = [&](const lsLocation& location, optional<QueryTypeId> declaring_type) -> std::string {
|
auto format_location =
|
||||||
|
[&](const lsLocation& location,
|
||||||
|
optional<QueryTypeId> declaring_type) -> std::string {
|
||||||
std::string base;
|
std::string base;
|
||||||
|
|
||||||
if (declaring_type) {
|
if (declaring_type) {
|
||||||
@ -774,8 +843,10 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(QueryDatabase
|
|||||||
NonElidedVector<Out_CqueryCallTree::CallEntry> result;
|
NonElidedVector<Out_CqueryCallTree::CallEntry> result;
|
||||||
std::unordered_set<QueryLocation> seen_locations;
|
std::unordered_set<QueryLocation> seen_locations;
|
||||||
|
|
||||||
auto handle_caller = [&](QueryFuncRef caller, Out_CqueryCallTree::CallType call_type) {
|
auto handle_caller = [&](QueryFuncRef caller,
|
||||||
optional<lsLocation> call_location = GetLsLocation(db, working_files, caller.loc);
|
Out_CqueryCallTree::CallType call_type) {
|
||||||
|
optional<lsLocation> call_location =
|
||||||
|
GetLsLocation(db, working_files, caller.loc);
|
||||||
if (!call_location)
|
if (!call_location)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -803,14 +874,15 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(QueryDatabase
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Out_CqueryCallTree::CallEntry call_entry;
|
Out_CqueryCallTree::CallEntry call_entry;
|
||||||
call_entry.name = call_func->def.short_name + " (" + format_location(*call_location, call_func->def.declaring_type) + ")";
|
call_entry.name =
|
||||||
|
call_func->def.short_name + " (" +
|
||||||
|
format_location(*call_location, call_func->def.declaring_type) + ")";
|
||||||
call_entry.usr = call_func->def.usr;
|
call_entry.usr = call_func->def.usr;
|
||||||
call_entry.location = *call_location;
|
call_entry.location = *call_location;
|
||||||
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, *call_func);
|
call_entry.hasCallers = HasCallersOnSelfOrBaseOrDerived(db, *call_func);
|
||||||
call_entry.callType = call_type;
|
call_entry.callType = call_type;
|
||||||
result.push_back(call_entry);
|
result.push_back(call_entry);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// TODO: See if we can do a better job here. Need more information from
|
// TODO: See if we can do a better job here. Need more information from
|
||||||
// the indexer.
|
// the indexer.
|
||||||
Out_CqueryCallTree::CallEntry call_entry;
|
Out_CqueryCallTree::CallEntry call_entry;
|
||||||
@ -823,9 +895,12 @@ NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(QueryDatabase
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<QueryFuncRef> base_callers = GetCallersForAllBaseFunctions(db, *root_func);
|
std::vector<QueryFuncRef> base_callers =
|
||||||
std::vector<QueryFuncRef> derived_callers = GetCallersForAllDerivedFunctions(db, *root_func);
|
GetCallersForAllBaseFunctions(db, *root_func);
|
||||||
result.reserve(root_func->callers.size() + base_callers.size() + derived_callers.size());
|
std::vector<QueryFuncRef> derived_callers =
|
||||||
|
GetCallersForAllDerivedFunctions(db, *root_func);
|
||||||
|
result.reserve(root_func->callers.size() + base_callers.size() +
|
||||||
|
derived_callers.size());
|
||||||
|
|
||||||
for (QueryFuncRef caller : root_func->callers)
|
for (QueryFuncRef caller : root_func->callers)
|
||||||
handle_caller(caller, Out_CqueryCallTree::CallType::Direct);
|
handle_caller(caller, Out_CqueryCallTree::CallType::Direct);
|
||||||
|
@ -7,31 +7,59 @@
|
|||||||
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
|
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const QueryTypeId& id);
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const QueryFuncId& id);
|
const QueryTypeId& id);
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const QueryVarId& id);
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db, const SymbolIdx& symbol);
|
const QueryFuncId& id);
|
||||||
optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db, const SymbolIdx& symbol);
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
|
const QueryVarId& id);
|
||||||
|
optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol);
|
||||||
|
optional<QueryLocation> GetDefinitionExtentOfSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol);
|
||||||
std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol);
|
std::string GetHoverForSymbol(QueryDatabase* db, const SymbolIdx& symbol);
|
||||||
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db, const SymbolIdx& symbol);
|
optional<QueryFileId> GetDeclarationFileForSymbol(QueryDatabase* db,
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryFuncRef>& refs);
|
const SymbolIdx& symbol);
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryTypeId>& ids);
|
std::vector<QueryLocation> ToQueryLocation(
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryFuncId>& ids);
|
QueryDatabase* db,
|
||||||
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db, const std::vector<QueryVarId>& ids);
|
const std::vector<QueryFuncRef>& refs);
|
||||||
std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db, const SymbolIdx& symbol);
|
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db,
|
||||||
std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(QueryDatabase* db, const SymbolIdx& symbol);
|
const std::vector<QueryTypeId>& ids);
|
||||||
optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling(QueryDatabase* db, QueryFunc& func);
|
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db,
|
||||||
|
const std::vector<QueryFuncId>& ids);
|
||||||
|
std::vector<QueryLocation> ToQueryLocation(QueryDatabase* db,
|
||||||
|
const std::vector<QueryVarId>& ids);
|
||||||
|
std::vector<QueryLocation> GetUsesOfSymbol(QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol);
|
||||||
|
std::vector<QueryLocation> GetDeclarationsOfSymbolForGotoDefinition(
|
||||||
|
QueryDatabase* db,
|
||||||
|
const SymbolIdx& symbol);
|
||||||
|
optional<QueryLocation> GetBaseDefinitionOrDeclarationSpelling(
|
||||||
|
QueryDatabase* db,
|
||||||
|
QueryFunc& func);
|
||||||
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root);
|
bool HasCallersOnSelfOrBaseOrDerived(QueryDatabase* db, QueryFunc& root);
|
||||||
std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db, QueryFunc& root);
|
std::vector<QueryFuncRef> GetCallersForAllBaseFunctions(QueryDatabase* db,
|
||||||
std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db, QueryFunc& root);
|
QueryFunc& root);
|
||||||
optional<lsPosition> GetLsPosition(WorkingFile* working_file, const Position& position);
|
std::vector<QueryFuncRef> GetCallersForAllDerivedFunctions(QueryDatabase* db,
|
||||||
|
QueryFunc& root);
|
||||||
|
optional<lsPosition> GetLsPosition(WorkingFile* working_file,
|
||||||
|
const Position& position);
|
||||||
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location);
|
optional<lsRange> GetLsRange(WorkingFile* working_file, const Range& location);
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id, std::string* path);
|
lsDocumentUri GetLsDocumentUri(QueryDatabase* db,
|
||||||
|
QueryFileId file_id,
|
||||||
|
std::string* path);
|
||||||
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id);
|
lsDocumentUri GetLsDocumentUri(QueryDatabase* db, QueryFileId file_id);
|
||||||
optional<lsLocation> GetLsLocation(QueryDatabase* db, WorkingFiles* working_files, const QueryLocation& location);
|
optional<lsLocation> GetLsLocation(QueryDatabase* db,
|
||||||
NonElidedVector<lsLocation> GetLsLocations(QueryDatabase* db, WorkingFiles* working_files, const std::vector<QueryLocation>& locations);
|
WorkingFiles* working_files,
|
||||||
|
const QueryLocation& location);
|
||||||
|
NonElidedVector<lsLocation> GetLsLocations(
|
||||||
|
QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
const std::vector<QueryLocation>& locations);
|
||||||
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
// Returns a symbol. The symbol will have *NOT* have a location assigned.
|
||||||
optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db, WorkingFiles* working_files, SymbolIdx symbol);
|
optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
SymbolIdx symbol);
|
||||||
|
|
||||||
struct CommonCodeLensParams {
|
struct CommonCodeLensParams {
|
||||||
std::vector<TCodeLens>* result;
|
std::vector<TCodeLens>* result;
|
||||||
@ -40,21 +68,43 @@ struct CommonCodeLensParams {
|
|||||||
WorkingFile* working_file;
|
WorkingFile* working_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddCodeLens(
|
void AddCodeLens(const char* singular,
|
||||||
const char* singular,
|
const char* plural,
|
||||||
const char* plural,
|
CommonCodeLensParams* common,
|
||||||
CommonCodeLensParams* common,
|
QueryLocation loc,
|
||||||
QueryLocation loc,
|
const std::vector<QueryLocation>& uses,
|
||||||
const std::vector<QueryLocation>& uses,
|
optional<QueryLocation> excluded,
|
||||||
optional<QueryLocation> excluded,
|
bool force_display);
|
||||||
bool force_display);
|
|
||||||
|
|
||||||
lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db, WorkingFiles* working_files, const std::vector<QueryLocation>& locations, const std::string& new_text);
|
lsWorkspaceEdit BuildWorkspaceEdit(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
const std::vector<QueryLocation>& locations,
|
||||||
|
const std::string& new_text);
|
||||||
|
|
||||||
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file, QueryFile* file, lsPosition position);
|
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
||||||
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHierarchyForType(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root);
|
QueryFile* file,
|
||||||
optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForType(QueryDatabase* db, WorkingFiles* working_files, QueryTypeId root_id);
|
lsPosition position);
|
||||||
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry> BuildParentInheritanceHierarchyForFunc(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root);
|
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
optional<Out_CqueryTypeHierarchyTree::TypeEntry> BuildInheritanceHierarchyForFunc(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root_id);
|
BuildParentInheritanceHierarchyForType(QueryDatabase* db,
|
||||||
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root);
|
WorkingFiles* working_files,
|
||||||
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(QueryDatabase* db, WorkingFiles* working_files, QueryFuncId root);
|
QueryTypeId root);
|
||||||
|
optional<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
|
BuildInheritanceHierarchyForType(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryTypeId root_id);
|
||||||
|
NonElidedVector<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
|
BuildParentInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root);
|
||||||
|
optional<Out_CqueryTypeHierarchyTree::TypeEntry>
|
||||||
|
BuildInheritanceHierarchyForFunc(QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root_id);
|
||||||
|
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildInitialCallTree(
|
||||||
|
QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root);
|
||||||
|
NonElidedVector<Out_CqueryCallTree::CallEntry> BuildExpandCallTree(
|
||||||
|
QueryDatabase* db,
|
||||||
|
WorkingFiles* working_files,
|
||||||
|
QueryFuncId root);
|
@ -49,7 +49,6 @@ void Reflect(Writer& visitor, std::string& value) {
|
|||||||
visitor.String(value.c_str(), (rapidjson::SizeType)value.size());
|
visitor.String(value.c_str(), (rapidjson::SizeType)value.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ReflectMember
|
// ReflectMember
|
||||||
void ReflectMember(Writer& visitor, const char* name, std::string& value) {
|
void ReflectMember(Writer& visitor, const char* name, std::string& value) {
|
||||||
if (value.empty())
|
if (value.empty())
|
||||||
@ -58,20 +57,9 @@ void ReflectMember(Writer& visitor, const char* name, std::string& value) {
|
|||||||
Reflect(visitor, value);
|
Reflect(visitor, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Move this to indexer.cc
|
// TODO: Move this to indexer.cc
|
||||||
|
|
||||||
template<typename TVisitor>
|
template <typename TVisitor>
|
||||||
void Reflect(TVisitor& visitor, IndexType& value) {
|
void Reflect(TVisitor& visitor, IndexType& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER2("id", value.id);
|
REFLECT_MEMBER2("id", value.id);
|
||||||
@ -91,8 +79,7 @@ void Reflect(TVisitor& visitor, IndexType& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TVisitor>
|
||||||
template<typename TVisitor>
|
|
||||||
void Reflect(TVisitor& visitor, IndexFunc& value) {
|
void Reflect(TVisitor& visitor, IndexFunc& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER2("id", value.id);
|
REFLECT_MEMBER2("id", value.id);
|
||||||
@ -111,8 +98,7 @@ void Reflect(TVisitor& visitor, IndexFunc& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename TVisitor>
|
||||||
template<typename TVisitor>
|
|
||||||
void Reflect(TVisitor& visitor, IndexVar& value) {
|
void Reflect(TVisitor& visitor, IndexVar& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
REFLECT_MEMBER2("id", value.id);
|
REFLECT_MEMBER2("id", value.id);
|
||||||
@ -130,7 +116,6 @@ void Reflect(TVisitor& visitor, IndexVar& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// IndexFile
|
// IndexFile
|
||||||
bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
|
bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
|
||||||
auto it = value.id_cache.usr_to_type_id.find("");
|
auto it = value.id_cache.usr_to_type_id.find("");
|
||||||
@ -143,7 +128,7 @@ bool ReflectMemberStart(Writer& visitor, IndexFile& value) {
|
|||||||
DefaultReflectMemberStart(visitor);
|
DefaultReflectMemberStart(visitor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template<typename TVisitor>
|
template <typename TVisitor>
|
||||||
void Reflect(TVisitor& visitor, IndexFile& value) {
|
void Reflect(TVisitor& visitor, IndexFile& value) {
|
||||||
REFLECT_MEMBER_START();
|
REFLECT_MEMBER_START();
|
||||||
if (!gTestOutputMode) {
|
if (!gTestOutputMode) {
|
||||||
@ -161,18 +146,12 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
|
|||||||
REFLECT_MEMBER_END();
|
REFLECT_MEMBER_END();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::string Serialize(IndexFile& file) {
|
std::string Serialize(IndexFile& file) {
|
||||||
rapidjson::StringBuffer output;
|
rapidjson::StringBuffer output;
|
||||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||||
//Writer writer(output);
|
// Writer writer(output);
|
||||||
writer.SetFormatOptions(
|
writer.SetFormatOptions(
|
||||||
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
||||||
writer.SetIndent(' ', 2);
|
writer.SetIndent(' ', 2);
|
||||||
|
|
||||||
Reflect(writer, file);
|
Reflect(writer, file);
|
||||||
@ -180,7 +159,9 @@ std::string Serialize(IndexFile& file) {
|
|||||||
return output.GetString();
|
return output.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IndexFile> Deserialize(std::string path, std::string serialized, optional<int> expected_version) {
|
std::unique_ptr<IndexFile> Deserialize(std::string path,
|
||||||
|
std::string serialized,
|
||||||
|
optional<int> expected_version) {
|
||||||
rapidjson::Document reader;
|
rapidjson::Document reader;
|
||||||
reader.Parse(serialized.c_str());
|
reader.Parse(serialized.c_str());
|
||||||
if (reader.HasParseError())
|
if (reader.HasParseError())
|
||||||
|
126
src/serializer.h
126
src/serializer.h
@ -9,84 +9,63 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
using Reader = rapidjson::GenericValue<rapidjson::UTF8<>>;
|
using Reader = rapidjson::GenericValue<rapidjson::UTF8<>>;
|
||||||
using Writer = rapidjson::Writer<rapidjson::StringBuffer>;
|
using Writer = rapidjson::Writer<rapidjson::StringBuffer>;
|
||||||
struct IndexFile;
|
struct IndexFile;
|
||||||
|
|
||||||
#define REFLECT_MEMBER_START() \
|
#define REFLECT_MEMBER_START() \
|
||||||
if (!ReflectMemberStart(visitor, value)) return
|
if (!ReflectMemberStart(visitor, value)) \
|
||||||
#define REFLECT_MEMBER_START1(value) \
|
return
|
||||||
if (!ReflectMemberStart(visitor, value)) return
|
#define REFLECT_MEMBER_START1(value) \
|
||||||
#define REFLECT_MEMBER_END() \
|
if (!ReflectMemberStart(visitor, value)) \
|
||||||
ReflectMemberEnd(visitor, value);
|
return
|
||||||
#define REFLECT_MEMBER_END1(value) \
|
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor, value);
|
||||||
ReflectMemberEnd(visitor, value);
|
#define REFLECT_MEMBER_END1(value) ReflectMemberEnd(visitor, value);
|
||||||
#define REFLECT_MEMBER(name) \
|
#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name)
|
||||||
ReflectMember(visitor, #name, value.name)
|
#define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value)
|
||||||
#define REFLECT_MEMBER2(name, value) \
|
|
||||||
ReflectMember(visitor, name, value)
|
|
||||||
|
|
||||||
|
#define MAKE_REFLECT_TYPE_PROXY(type, as_type) \
|
||||||
#define MAKE_REFLECT_TYPE_PROXY(type, as_type) \
|
template <typename TVisitor> \
|
||||||
template<typename TVisitor> \
|
|
||||||
void Reflect(TVisitor& visitor, type& value) { \
|
void Reflect(TVisitor& visitor, type& value) { \
|
||||||
auto value0 = static_cast<as_type>(value); \
|
auto value0 = static_cast<as_type>(value); \
|
||||||
Reflect(visitor, value0); \
|
Reflect(visitor, value0); \
|
||||||
value = static_cast<type>(value0); \
|
value = static_cast<type>(value0); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _MAPPABLE_REFLECT_MEMBER(name) \
|
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
|
||||||
REFLECT_MEMBER(name);
|
|
||||||
|
|
||||||
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
|
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
|
||||||
template<typename TVisitor> \
|
template <typename TVisitor> \
|
||||||
void Reflect(TVisitor& visitor, type& value) { \
|
void Reflect(TVisitor& visitor, type& value) { \
|
||||||
REFLECT_MEMBER_START(); \
|
REFLECT_MEMBER_START(); \
|
||||||
REFLECT_MEMBER_END(); \
|
REFLECT_MEMBER_END(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAKE_REFLECT_STRUCT(type, ...) \
|
#define MAKE_REFLECT_STRUCT(type, ...) \
|
||||||
template<typename TVisitor> \
|
template <typename TVisitor> \
|
||||||
void Reflect(TVisitor& visitor, type& value) { \
|
void Reflect(TVisitor& visitor, type& value) { \
|
||||||
REFLECT_MEMBER_START(); \
|
REFLECT_MEMBER_START(); \
|
||||||
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
|
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
|
||||||
REFLECT_MEMBER_END(); \
|
REFLECT_MEMBER_END(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define _MAPPABLE_REFLECT_ARRAY(name) \
|
#define _MAPPABLE_REFLECT_ARRAY(name) Reflect(visitor, value.name);
|
||||||
Reflect(visitor, value.name);
|
|
||||||
|
|
||||||
// Reflects the struct so it is serialized as an array instead of an object.
|
// Reflects the struct so it is serialized as an array instead of an object.
|
||||||
// This currently only supports writers.
|
// This currently only supports writers.
|
||||||
#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \
|
#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \
|
||||||
inline void Reflect(Writer& visitor, type& value) { \
|
inline void Reflect(Writer& visitor, type& value) { \
|
||||||
visitor.StartArray(); \
|
visitor.StartArray(); \
|
||||||
MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \
|
MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \
|
||||||
visitor.EndArray(); \
|
visitor.EndArray(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct NonElidedVector : public std::vector<T> {};
|
struct NonElidedVector : public std::vector<T> {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// API:
|
// API:
|
||||||
/*
|
/*
|
||||||
template<typename TVisitor, typename T>
|
template<typename TVisitor, typename T>
|
||||||
@ -108,7 +87,6 @@ void ReflectMemberEnd(TVisitor& visitor, T& value) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// int16_t
|
// int16_t
|
||||||
void Reflect(Reader& visitor, int16_t& value);
|
void Reflect(Reader& visitor, int16_t& value);
|
||||||
void Reflect(Writer& visitor, int16_t& value);
|
void Reflect(Writer& visitor, int16_t& value);
|
||||||
@ -128,21 +106,15 @@ void Reflect(Writer& visitor, bool& value);
|
|||||||
void Reflect(Reader& visitor, std::string& value);
|
void Reflect(Reader& visitor, std::string& value);
|
||||||
void Reflect(Writer& visitor, std::string& value);
|
void Reflect(Writer& visitor, std::string& value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Writer:
|
// Writer:
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Reflect(Writer& visitor, std::vector<T>& values) {
|
void Reflect(Writer& visitor, std::vector<T>& values) {
|
||||||
visitor.StartArray();
|
visitor.StartArray();
|
||||||
for (auto& value : values)
|
for (auto& value : values)
|
||||||
Reflect(visitor, value);
|
Reflect(visitor, value);
|
||||||
visitor.EndArray();
|
visitor.EndArray();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Reflect(Writer& visitor, optional<T> value) {
|
void Reflect(Writer& visitor, optional<T> value) {
|
||||||
if (value)
|
if (value)
|
||||||
Reflect(visitor, value.value());
|
Reflect(visitor, value.value());
|
||||||
@ -150,21 +122,21 @@ void Reflect(Writer& visitor, optional<T> value) {
|
|||||||
inline void DefaultReflectMemberStart(Writer& visitor) {
|
inline void DefaultReflectMemberStart(Writer& visitor) {
|
||||||
visitor.StartObject();
|
visitor.StartObject();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool ReflectMemberStart(Writer& visitor, T& value) {
|
bool ReflectMemberStart(Writer& visitor, T& value) {
|
||||||
visitor.StartObject();
|
visitor.StartObject();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMemberEnd(Writer& visitor, T& value) {
|
void ReflectMemberEnd(Writer& visitor, T& value) {
|
||||||
visitor.EndObject();
|
visitor.EndObject();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMember(Writer& visitor, const char* name, T& value) {
|
void ReflectMember(Writer& visitor, const char* name, T& value) {
|
||||||
visitor.Key(name);
|
visitor.Key(name);
|
||||||
Reflect(visitor, value);
|
Reflect(visitor, value);
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMember(Writer& visitor, const char* name, std::vector<T>& values) {
|
void ReflectMember(Writer& visitor, const char* name, std::vector<T>& values) {
|
||||||
if (values.empty())
|
if (values.empty())
|
||||||
return;
|
return;
|
||||||
@ -174,15 +146,17 @@ void ReflectMember(Writer& visitor, const char* name, std::vector<T>& values) {
|
|||||||
Reflect(visitor, value);
|
Reflect(visitor, value);
|
||||||
visitor.EndArray();
|
visitor.EndArray();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMember(Writer& visitor, const char* name, NonElidedVector<T>& values) {
|
void ReflectMember(Writer& visitor,
|
||||||
|
const char* name,
|
||||||
|
NonElidedVector<T>& values) {
|
||||||
visitor.Key(name);
|
visitor.Key(name);
|
||||||
visitor.StartArray();
|
visitor.StartArray();
|
||||||
for (auto& value : values)
|
for (auto& value : values)
|
||||||
Reflect(visitor, value);
|
Reflect(visitor, value);
|
||||||
visitor.EndArray();
|
visitor.EndArray();
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
|
void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return;
|
return;
|
||||||
@ -192,7 +166,7 @@ void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
|
|||||||
void ReflectMember(Writer& visitor, const char* name, std::string& value);
|
void ReflectMember(Writer& visitor, const char* name, std::string& value);
|
||||||
|
|
||||||
// Reader:
|
// Reader:
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Reflect(Reader& visitor, std::vector<T>& values) {
|
void Reflect(Reader& visitor, std::vector<T>& values) {
|
||||||
for (auto& entry : visitor.GetArray()) {
|
for (auto& entry : visitor.GetArray()) {
|
||||||
T entry_value;
|
T entry_value;
|
||||||
@ -200,20 +174,20 @@ void Reflect(Reader& visitor, std::vector<T>& values) {
|
|||||||
values.push_back(entry_value);
|
values.push_back(entry_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void Reflect(Reader& visitor, optional<T>& value) {
|
void Reflect(Reader& visitor, optional<T>& value) {
|
||||||
T real_value;
|
T real_value;
|
||||||
Reflect(visitor, real_value);
|
Reflect(visitor, real_value);
|
||||||
value = real_value;
|
value = real_value;
|
||||||
}
|
}
|
||||||
inline void DefaultReflectMemberStart(Reader& visitor) {}
|
inline void DefaultReflectMemberStart(Reader& visitor) {}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool ReflectMemberStart(Reader& visitor, T& value) {
|
bool ReflectMemberStart(Reader& visitor, T& value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMemberEnd(Reader& visitor, T& value) {}
|
void ReflectMemberEnd(Reader& visitor, T& value) {}
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void ReflectMember(Reader& visitor, const char* name, T& value) {
|
void ReflectMember(Reader& visitor, const char* name, T& value) {
|
||||||
auto it = visitor.FindMember(name);
|
auto it = visitor.FindMember(name);
|
||||||
if (it != visitor.MemberEnd()) {
|
if (it != visitor.MemberEnd()) {
|
||||||
@ -223,6 +197,8 @@ void ReflectMember(Reader& visitor, const char* name, T& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string Serialize(IndexFile& file);
|
std::string Serialize(IndexFile& file);
|
||||||
std::unique_ptr<IndexFile> Deserialize(std::string path, std::string serialized, optional<int> expected_version);
|
std::unique_ptr<IndexFile> Deserialize(std::string path,
|
||||||
|
std::string serialized,
|
||||||
|
optional<int> expected_version);
|
||||||
|
|
||||||
void SetTestOutputMode();
|
void SetTestOutputMode();
|
||||||
|
@ -2,181 +2,181 @@
|
|||||||
|
|
||||||
// See http://stackoverflow.com/a/2029106.
|
// See http://stackoverflow.com/a/2029106.
|
||||||
const char* kStandardLibraryIncludes[177] = {
|
const char* kStandardLibraryIncludes[177] = {
|
||||||
"aio.h",
|
"aio.h",
|
||||||
"algorithm",
|
"algorithm",
|
||||||
"any",
|
"any",
|
||||||
"arpa/inet.h",
|
"arpa/inet.h",
|
||||||
"array",
|
"array",
|
||||||
"assert.h",
|
"assert.h",
|
||||||
"atomic",
|
"atomic",
|
||||||
"bitset",
|
"bitset",
|
||||||
"cassert",
|
"cassert",
|
||||||
"ccomplex",
|
"ccomplex",
|
||||||
"cctype",
|
"cctype",
|
||||||
"cerrno",
|
"cerrno",
|
||||||
"cfenv",
|
"cfenv",
|
||||||
"cfloat",
|
"cfloat",
|
||||||
"chrono",
|
"chrono",
|
||||||
"cinttypes",
|
"cinttypes",
|
||||||
"ciso646",
|
"ciso646",
|
||||||
"climits",
|
"climits",
|
||||||
"clocale",
|
"clocale",
|
||||||
"cmath",
|
"cmath",
|
||||||
"codecvt",
|
"codecvt",
|
||||||
"complex",
|
"complex",
|
||||||
"complex.h",
|
"complex.h",
|
||||||
"condition_variable",
|
"condition_variable",
|
||||||
"cpio.h",
|
"cpio.h",
|
||||||
"csetjmp",
|
"csetjmp",
|
||||||
"csignal",
|
"csignal",
|
||||||
"cstdalign",
|
"cstdalign",
|
||||||
"cstdarg",
|
"cstdarg",
|
||||||
"cstdbool",
|
"cstdbool",
|
||||||
"cstddef",
|
"cstddef",
|
||||||
"cstdint",
|
"cstdint",
|
||||||
"cstdio",
|
"cstdio",
|
||||||
"cstdlib",
|
"cstdlib",
|
||||||
"cstring",
|
"cstring",
|
||||||
"ctgmath",
|
"ctgmath",
|
||||||
"ctime",
|
"ctime",
|
||||||
"ctype.h",
|
"ctype.h",
|
||||||
"cuchar",
|
"cuchar",
|
||||||
"curses.h",
|
"curses.h",
|
||||||
"cwchar",
|
"cwchar",
|
||||||
"cwctype",
|
"cwctype",
|
||||||
"deque",
|
"deque",
|
||||||
"dirent.h",
|
"dirent.h",
|
||||||
"dlfcn.h",
|
"dlfcn.h",
|
||||||
"errno.h",
|
"errno.h",
|
||||||
"exception",
|
"exception",
|
||||||
"execution",
|
"execution",
|
||||||
"fcntl.h",
|
"fcntl.h",
|
||||||
"fenv.h",
|
"fenv.h",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
"float.h",
|
"float.h",
|
||||||
"fmtmsg.h",
|
"fmtmsg.h",
|
||||||
"fnmatch.h",
|
"fnmatch.h",
|
||||||
"forward_list",
|
"forward_list",
|
||||||
"fstream",
|
"fstream",
|
||||||
"ftw.h",
|
"ftw.h",
|
||||||
"functional",
|
"functional",
|
||||||
"future",
|
"future",
|
||||||
"glob.h",
|
"glob.h",
|
||||||
"grp.h",
|
"grp.h",
|
||||||
"iconv.h",
|
"iconv.h",
|
||||||
"initializer_list",
|
"initializer_list",
|
||||||
"inttypes.h",
|
"inttypes.h",
|
||||||
"iomanip",
|
"iomanip",
|
||||||
"ios",
|
"ios",
|
||||||
"iosfwd",
|
"iosfwd",
|
||||||
"iostream",
|
"iostream",
|
||||||
"iso646.h",
|
"iso646.h",
|
||||||
"istream",
|
"istream",
|
||||||
"iterator",
|
"iterator",
|
||||||
"langinfo.h",
|
"langinfo.h",
|
||||||
"libgen.h",
|
"libgen.h",
|
||||||
"limits",
|
"limits",
|
||||||
"limits.h",
|
"limits.h",
|
||||||
"list",
|
"list",
|
||||||
"locale",
|
"locale",
|
||||||
"locale.h",
|
"locale.h",
|
||||||
"map",
|
"map",
|
||||||
"math.h",
|
"math.h",
|
||||||
"memory",
|
"memory",
|
||||||
"memory_resource",
|
"memory_resource",
|
||||||
"monetary.h",
|
"monetary.h",
|
||||||
"mqueue.h",
|
"mqueue.h",
|
||||||
"mutex",
|
"mutex",
|
||||||
"ndbm.h",
|
"ndbm.h",
|
||||||
"net/if.h",
|
"net/if.h",
|
||||||
"netdb.h",
|
"netdb.h",
|
||||||
"netinet/in.h",
|
"netinet/in.h",
|
||||||
"netinet/tcp.h",
|
"netinet/tcp.h",
|
||||||
"new",
|
"new",
|
||||||
"nl_types.h",
|
"nl_types.h",
|
||||||
"numeric",
|
"numeric",
|
||||||
"optional",
|
"optional",
|
||||||
"ostream",
|
"ostream",
|
||||||
"poll.h",
|
"poll.h",
|
||||||
"pthread.h",
|
"pthread.h",
|
||||||
"pwd.h",
|
"pwd.h",
|
||||||
"queue",
|
"queue",
|
||||||
"random",
|
"random",
|
||||||
"ratio",
|
"ratio",
|
||||||
"regex",
|
"regex",
|
||||||
"regex.h",
|
"regex.h",
|
||||||
"sched.h",
|
"sched.h",
|
||||||
"scoped_allocator",
|
"scoped_allocator",
|
||||||
"search.h",
|
"search.h",
|
||||||
"semaphore.h",
|
"semaphore.h",
|
||||||
"set",
|
"set",
|
||||||
"setjmp.h",
|
"setjmp.h",
|
||||||
"shared_mutex",
|
"shared_mutex",
|
||||||
"signal.h",
|
"signal.h",
|
||||||
"spawn.h",
|
"spawn.h",
|
||||||
"sstream",
|
"sstream",
|
||||||
"stack",
|
"stack",
|
||||||
"stdalign.h",
|
"stdalign.h",
|
||||||
"stdarg.h",
|
"stdarg.h",
|
||||||
"stdatomic.h",
|
"stdatomic.h",
|
||||||
"stdbool.h",
|
"stdbool.h",
|
||||||
"stddef.h",
|
"stddef.h",
|
||||||
"stdexcept",
|
"stdexcept",
|
||||||
"stdint.h",
|
"stdint.h",
|
||||||
"stdio.h",
|
"stdio.h",
|
||||||
"stdlib.h",
|
"stdlib.h",
|
||||||
"stdnoreturn.h",
|
"stdnoreturn.h",
|
||||||
"streambuf",
|
"streambuf",
|
||||||
"string",
|
"string",
|
||||||
"string.h",
|
"string.h",
|
||||||
"string_view",
|
"string_view",
|
||||||
"strings.h",
|
"strings.h",
|
||||||
"stropts.h",
|
"stropts.h",
|
||||||
"strstream",
|
"strstream",
|
||||||
"sys/ipc.h",
|
"sys/ipc.h",
|
||||||
"sys/mman.h",
|
"sys/mman.h",
|
||||||
"sys/msg.h",
|
"sys/msg.h",
|
||||||
"sys/resource.h",
|
"sys/resource.h",
|
||||||
"sys/select.h",
|
"sys/select.h",
|
||||||
"sys/sem.h",
|
"sys/sem.h",
|
||||||
"sys/shm.h",
|
"sys/shm.h",
|
||||||
"sys/socket.h",
|
"sys/socket.h",
|
||||||
"sys/stat.h",
|
"sys/stat.h",
|
||||||
"sys/statvfs.h",
|
"sys/statvfs.h",
|
||||||
"sys/time.h",
|
"sys/time.h",
|
||||||
"sys/times.h",
|
"sys/times.h",
|
||||||
"sys/types.h",
|
"sys/types.h",
|
||||||
"sys/uio.h",
|
"sys/uio.h",
|
||||||
"sys/un.h",
|
"sys/un.h",
|
||||||
"sys/utsname.h",
|
"sys/utsname.h",
|
||||||
"sys/wait.h",
|
"sys/wait.h",
|
||||||
"syslog.h",
|
"syslog.h",
|
||||||
"system_error",
|
"system_error",
|
||||||
"tar.h",
|
"tar.h",
|
||||||
"term.h",
|
"term.h",
|
||||||
"termios.h",
|
"termios.h",
|
||||||
"tgmath.h",
|
"tgmath.h",
|
||||||
"thread",
|
"thread",
|
||||||
"threads.h",
|
"threads.h",
|
||||||
"time.h",
|
"time.h",
|
||||||
"trace.h",
|
"trace.h",
|
||||||
"tuple",
|
"tuple",
|
||||||
"type_traits",
|
"type_traits",
|
||||||
"typeindex",
|
"typeindex",
|
||||||
"typeinfo",
|
"typeinfo",
|
||||||
"uchar.h",
|
"uchar.h",
|
||||||
"ulimit.h",
|
"ulimit.h",
|
||||||
"uncntrl.h",
|
"uncntrl.h",
|
||||||
"unistd.h",
|
"unistd.h",
|
||||||
"unordered_map",
|
"unordered_map",
|
||||||
"unordered_set",
|
"unordered_set",
|
||||||
"utility",
|
"utility",
|
||||||
"utime.h",
|
"utime.h",
|
||||||
"utmpx.h",
|
"utmpx.h",
|
||||||
"valarray",
|
"valarray",
|
||||||
"variant",
|
"variant",
|
||||||
"vector",
|
"vector",
|
||||||
"wchar.h",
|
"wchar.h",
|
||||||
"wctype.h",
|
"wctype.h",
|
||||||
"wordexp.h",
|
"wordexp.h",
|
||||||
};
|
};
|
118
src/test.cc
118
src/test.cc
@ -14,7 +14,7 @@ std::string ToString(const rapidjson::Document& document) {
|
|||||||
rapidjson::StringBuffer buffer;
|
rapidjson::StringBuffer buffer;
|
||||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||||
writer.SetFormatOptions(
|
writer.SetFormatOptions(
|
||||||
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
||||||
writer.SetIndent(' ', 2);
|
writer.SetIndent(' ', 2);
|
||||||
|
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
@ -22,16 +22,24 @@ std::string ToString(const rapidjson::Document& document) {
|
|||||||
return buffer.GetString();
|
return buffer.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
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_actual_output = ToString(actual);
|
||||||
std::vector<std::string> actual_output = SplitString(joined_actual_output, "\n");
|
std::vector<std::string> actual_output =
|
||||||
|
SplitString(joined_actual_output, "\n");
|
||||||
std::string joined_expected_output = ToString(expected);
|
std::string joined_expected_output = ToString(expected);
|
||||||
std::vector<std::string> expected_output = SplitString(joined_expected_output, "\n");
|
std::vector<std::string> expected_output =
|
||||||
|
SplitString(joined_expected_output, "\n");
|
||||||
|
|
||||||
std::cout << "[FAILED] " << path << " (section " << path_section << ")" << std::endl;
|
std::cout << "[FAILED] " << path << " (section " << path_section << ")"
|
||||||
std::cout << "Expected output for " << path << " (section " << path_section << "):" << std::endl;
|
<< std::endl;
|
||||||
|
std::cout << "Expected output for " << path << " (section " << path_section
|
||||||
|
<< "):" << std::endl;
|
||||||
std::cout << joined_expected_output << std::endl;
|
std::cout << joined_expected_output << std::endl;
|
||||||
std::cout << "Actual output for " << path << " (section " << path_section << "):" << std::endl;
|
std::cout << "Actual output for " << path << " (section " << path_section
|
||||||
|
<< "):" << std::endl;
|
||||||
std::cout << joined_actual_output << std::endl;
|
std::cout << joined_actual_output << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
@ -66,15 +74,19 @@ void DiffDocuments(std::string path, std::string path_section, rapidjson::Docume
|
|||||||
|
|
||||||
void VerifySerializeToFrom(IndexFile* file) {
|
void VerifySerializeToFrom(IndexFile* file) {
|
||||||
std::string expected = file->ToString();
|
std::string expected = file->ToString();
|
||||||
std::unique_ptr<IndexFile> result = Deserialize("--.cc", Serialize(*file), nullopt /*expected_version*/);
|
std::unique_ptr<IndexFile> result =
|
||||||
|
Deserialize("--.cc", Serialize(*file), nullopt /*expected_version*/);
|
||||||
std::string actual = result->ToString();
|
std::string actual = result->ToString();
|
||||||
if (expected != actual) {
|
if (expected != actual) {
|
||||||
std::cerr << "Serialization failure" << std::endl;;
|
std::cerr << "Serialization failure" << std::endl;
|
||||||
|
;
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FindExpectedOutputForFilename(std::string filename, const std::unordered_map<std::string, std::string>& expected) {
|
std::string FindExpectedOutputForFilename(
|
||||||
|
std::string filename,
|
||||||
|
const std::unordered_map<std::string, std::string>& expected) {
|
||||||
for (const auto& entry : expected) {
|
for (const auto& entry : expected) {
|
||||||
if (EndsWith(entry.first, filename))
|
if (EndsWith(entry.first, filename))
|
||||||
return entry.second;
|
return entry.second;
|
||||||
@ -86,7 +98,9 @@ std::string FindExpectedOutputForFilename(std::string filename, const std::unord
|
|||||||
return "{}";
|
return "{}";
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexFile* FindDbForPathEnding(const std::string& path, const std::vector<std::unique_ptr<IndexFile>>& dbs) {
|
IndexFile* FindDbForPathEnding(
|
||||||
|
const std::string& path,
|
||||||
|
const std::vector<std::unique_ptr<IndexFile>>& dbs) {
|
||||||
for (auto& db : dbs) {
|
for (auto& db : dbs) {
|
||||||
if (EndsWith(db->path, path))
|
if (EndsWith(db->path, path))
|
||||||
return db.get();
|
return db.get();
|
||||||
@ -101,48 +115,48 @@ void RunTests() {
|
|||||||
bool update_all = false;
|
bool update_all = false;
|
||||||
clang::Index index(1, 0);
|
clang::Index index(1, 0);
|
||||||
|
|
||||||
for (std::string path : GetFilesInFolder("tests", true /*recursive*/, true /*add_folder_to_path*/)) {
|
for (std::string path : GetFilesInFolder("tests", true /*recursive*/,
|
||||||
|
true /*add_folder_to_path*/)) {
|
||||||
float memory_before = GetProcessMemoryUsedInMb();
|
float memory_before = GetProcessMemoryUsedInMb();
|
||||||
float memory_after = -1.;
|
float memory_after = -1.;
|
||||||
|
|
||||||
{
|
{
|
||||||
//if (path != "tests/templates/specialized_func_definition.cc") continue;
|
// if (path != "tests/templates/specialized_func_definition.cc") continue;
|
||||||
//if (path != "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc") continue;
|
// if (path !=
|
||||||
//if (path != "tests/multi_file/funky_enum.cc") continue;
|
// "tests/templates/namespace_template_class_template_func_usage_folded_into_one.cc")
|
||||||
//if (path != "tests/multi_file/simple_impl.cc") continue;
|
// continue; if (path != "tests/multi_file/funky_enum.cc") continue; if
|
||||||
//if (path != "tests/inheritance/interface_pure_virtual.cc") continue;
|
// (path != "tests/multi_file/simple_impl.cc") continue; if (path !=
|
||||||
//if (path != "tests/_empty_test.cc") continue;
|
// "tests/inheritance/interface_pure_virtual.cc") continue; if (path !=
|
||||||
//if (path != "tests/declaration_vs_definition/func_associated_function_params.cc") continue;
|
// "tests/_empty_test.cc") continue; if (path !=
|
||||||
|
// "tests/declaration_vs_definition/func_associated_function_params.cc")
|
||||||
|
// continue;
|
||||||
|
|
||||||
//if (path != "tests/templates/template_class_type_usage_folded_into_one.cc") continue;
|
// if (path !=
|
||||||
//path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
// "tests/templates/template_class_type_usage_folded_into_one.cc")
|
||||||
|
// continue; path = "C:/Users/jacob/Desktop/superindex/indexer/" + path;
|
||||||
|
|
||||||
Config config;
|
Config config;
|
||||||
FileConsumer::SharedState file_consumer_shared;
|
FileConsumer::SharedState file_consumer_shared;
|
||||||
|
|
||||||
// Run test.
|
// Run test.
|
||||||
//std::cout << "[START] " << path << std::endl;
|
// std::cout << "[START] " << path << std::endl;
|
||||||
PerformanceImportFile perf;
|
PerformanceImportFile perf;
|
||||||
std::vector<std::unique_ptr<IndexFile>> dbs = Parse(
|
std::vector<std::unique_ptr<IndexFile>> dbs = Parse(
|
||||||
&config, &file_consumer_shared,
|
&config, &file_consumer_shared, path,
|
||||||
path,
|
{"-xc++", "-std=c++11",
|
||||||
{
|
"-IC:/Users/jacob/Desktop/cquery/third_party/",
|
||||||
"-xc++",
|
"-IC:/Users/jacob/Desktop/cquery/third_party/doctest/",
|
||||||
"-std=c++11",
|
"-IC:/Users/jacob/Desktop/cquery/third_party/rapidjson/include",
|
||||||
"-IC:/Users/jacob/Desktop/cquery/third_party/",
|
"-IC:/Users/jacob/Desktop/cquery/src",
|
||||||
"-IC:/Users/jacob/Desktop/cquery/third_party/doctest/",
|
"-isystemC:/Program Files (x86)/Microsoft Visual "
|
||||||
"-IC:/Users/jacob/Desktop/cquery/third_party/rapidjson/include",
|
"Studio/2017/Community/VC/Tools/MSVC/14.10.25017/include",
|
||||||
"-IC:/Users/jacob/Desktop/cquery/src",
|
"-isystemC:/Program Files (x86)/Windows "
|
||||||
"-isystemC:/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.10.25017/include",
|
"Kits/10/Include/10.0.15063.0/ucrt"},
|
||||||
"-isystemC:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt"
|
{}, &perf, &index, false /*dump_ast*/);
|
||||||
},
|
|
||||||
{},
|
|
||||||
&perf,
|
|
||||||
&index,
|
|
||||||
false /*dump_ast*/);
|
|
||||||
|
|
||||||
// Parse expected output from the test, parse it into JSON document.
|
// Parse expected output from the test, parse it into JSON document.
|
||||||
std::unordered_map<std::string, std::string> all_expected_output = ParseTestExpectation(path);
|
std::unordered_map<std::string, std::string> all_expected_output =
|
||||||
|
ParseTestExpectation(path);
|
||||||
for (auto& entry : all_expected_output) {
|
for (auto& entry : all_expected_output) {
|
||||||
const std::string& expected_path = entry.first;
|
const std::string& expected_path = entry.first;
|
||||||
const std::string& expected_output = entry.second;
|
const std::string& expected_output = entry.second;
|
||||||
@ -164,12 +178,12 @@ void RunTests() {
|
|||||||
|
|
||||||
if (actual == expected) {
|
if (actual == expected) {
|
||||||
std::cout << "[PASSED] " << path << std::endl;
|
std::cout << "[PASSED] " << path << std::endl;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DiffDocuments(path, expected_path, expected, actual);
|
DiffDocuments(path, expected_path, expected, actual);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "[Enter to continue - type u to update test, a to update all]";
|
std::cout
|
||||||
|
<< "[Enter to continue - type u to update test, a to update all]";
|
||||||
char c = 'u';
|
char c = 'u';
|
||||||
if (!update_all) {
|
if (!update_all) {
|
||||||
c = (char)std::cin.get();
|
c = (char)std::cin.get();
|
||||||
@ -180,9 +194,9 @@ void RunTests() {
|
|||||||
update_all = true;
|
update_all = true;
|
||||||
|
|
||||||
if (update_all || c == 'u') {
|
if (update_all || c == 'u') {
|
||||||
UpdateTestExpectation(path, expected_output, ToString(actual) + "\n");
|
UpdateTestExpectation(path, expected_output,
|
||||||
|
ToString(actual) + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,12 +204,16 @@ void RunTests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float memory_cleanup = GetProcessMemoryUsedInMb();
|
float memory_cleanup = GetProcessMemoryUsedInMb();
|
||||||
std::cerr << "[memory] before=" << memory_before << "mb, after=" << memory_after << "mb, cleanup=" << memory_cleanup << "mb" << std::endl;
|
std::cerr << "[memory] before=" << memory_before
|
||||||
|
<< "mb, after=" << memory_after
|
||||||
|
<< "mb, cleanup=" << memory_cleanup << "mb" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "[final presleep] " << GetProcessMemoryUsedInMb() << "mb" << std::endl;
|
std::cerr << "[final presleep] " << GetProcessMemoryUsedInMb() << "mb"
|
||||||
//std::this_thread::sleep_for(std::chrono::seconds(10));
|
<< std::endl;
|
||||||
//std::cerr << "[final postsleep] " << GetProcessMemoryUsedInMb() << "mb" << std::endl;
|
// std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||||
|
// std::cerr << "[final postsleep] " << GetProcessMemoryUsedInMb() << "mb" <<
|
||||||
|
// std::endl;
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
std::cerr << std::endl;
|
std::cerr << std::endl;
|
||||||
@ -204,5 +222,5 @@ void RunTests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ctor/dtor, copy ctor
|
// TODO: ctor/dtor, copy ctor
|
||||||
// TODO: Always pass IndexFile by pointer, ie, search and remove all IndexFile& refs.
|
// TODO: Always pass IndexFile by pointer, ie, search and remove all IndexFile&
|
||||||
|
// refs.
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void RunTests();
|
void RunTests();
|
@ -1,16 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "work_thread.h"
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
|
#include "work_thread.h"
|
||||||
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <queue>
|
|
||||||
#include <mutex>
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
// TODO: cleanup includes.
|
// TODO: cleanup includes.
|
||||||
|
|
||||||
@ -56,7 +58,7 @@ struct MultiQueueWaiter {
|
|||||||
// A threadsafe-queue. http://stackoverflow.com/a/16075550
|
// A threadsafe-queue. http://stackoverflow.com/a/16075550
|
||||||
template <class T>
|
template <class T>
|
||||||
struct ThreadedQueue : public BaseThreadQueue {
|
struct ThreadedQueue : public BaseThreadQueue {
|
||||||
public:
|
public:
|
||||||
ThreadedQueue() {
|
ThreadedQueue() {
|
||||||
owned_waiter_ = MakeUnique<MultiQueueWaiter>();
|
owned_waiter_ = MakeUnique<MultiQueueWaiter>();
|
||||||
waiter_ = owned_waiter_.get();
|
waiter_ = owned_waiter_.get();
|
||||||
@ -111,12 +113,11 @@ public:
|
|||||||
|
|
||||||
// Get the first element from the queue. Blocks until one is available.
|
// Get the first element from the queue. Blocks until one is available.
|
||||||
// Executes |action| with an acquired |mutex_|.
|
// Executes |action| with an acquired |mutex_|.
|
||||||
template<typename TAction>
|
template <typename TAction>
|
||||||
T DequeuePlusAction(TAction action) {
|
T DequeuePlusAction(TAction action) {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
waiter_->cv.wait(lock, [&]() {
|
waiter_->cv.wait(lock,
|
||||||
return !priority_.empty() || !queue_.empty();
|
[&]() { return !priority_.empty() || !queue_.empty(); });
|
||||||
});
|
|
||||||
|
|
||||||
if (!priority_.empty()) {
|
if (!priority_.empty()) {
|
||||||
auto val = std::move(priority_.front());
|
auto val = std::move(priority_.front());
|
||||||
@ -139,7 +140,7 @@ public:
|
|||||||
|
|
||||||
// Get the first element from the queue without blocking. Returns a null
|
// Get the first element from the queue without blocking. Returns a null
|
||||||
// value if the queue is empty.
|
// value if the queue is empty.
|
||||||
template<typename TAction>
|
template <typename TAction>
|
||||||
optional<T> TryDequeuePlusAction(TAction action) {
|
optional<T> TryDequeuePlusAction(TAction action) {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
if (priority_.empty() && queue_.empty())
|
if (priority_.empty() && queue_.empty())
|
||||||
|
14
src/timer.cc
14
src/timer.cc
@ -10,12 +10,15 @@ Timer::Timer() {
|
|||||||
|
|
||||||
long long Timer::ElapsedMicroseconds() const {
|
long long Timer::ElapsedMicroseconds() const {
|
||||||
std::chrono::time_point<Clock> end = Clock::now();
|
std::chrono::time_point<Clock> end = Clock::now();
|
||||||
return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
return std::chrono::duration_cast<std::chrono::microseconds>(end - start)
|
||||||
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
long long Timer::ElapsedMicrosecondsAndReset() {
|
long long Timer::ElapsedMicrosecondsAndReset() {
|
||||||
std::chrono::time_point<Clock> end = Clock::now();
|
std::chrono::time_point<Clock> end = Clock::now();
|
||||||
long long microseconds = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
long long microseconds =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(end - start)
|
||||||
|
.count();
|
||||||
Reset();
|
Reset();
|
||||||
return microseconds;
|
return microseconds;
|
||||||
}
|
}
|
||||||
@ -26,11 +29,14 @@ void Timer::Reset() {
|
|||||||
|
|
||||||
void Timer::ResetAndPrint(const std::string& message) {
|
void Timer::ResetAndPrint(const std::string& message) {
|
||||||
std::chrono::time_point<Clock> end = Clock::now();
|
std::chrono::time_point<Clock> end = Clock::now();
|
||||||
long long elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
long long elapsed =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(end - start)
|
||||||
|
.count();
|
||||||
|
|
||||||
long long milliseconds = elapsed / 1000;
|
long long milliseconds = elapsed / 1000;
|
||||||
long long remaining = elapsed - milliseconds;
|
long long remaining = elapsed - milliseconds;
|
||||||
|
|
||||||
LOG_S(INFO) << message << " took " << milliseconds << "." << remaining << "ms";
|
LOG_S(INFO) << message << " took " << milliseconds << "." << remaining
|
||||||
|
<< "ms";
|
||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
@ -17,12 +17,10 @@ struct TypedBidiMessageQueue {
|
|||||||
std::function<std::unique_ptr<TMessage>(Reader& visitor)>;
|
std::function<std::unique_ptr<TMessage>(Reader& visitor)>;
|
||||||
|
|
||||||
TypedBidiMessageQueue(const std::string& name, size_t buffer_size)
|
TypedBidiMessageQueue(const std::string& name, size_t buffer_size)
|
||||||
: for_server(
|
: for_server(Buffer::CreateSharedBuffer(name + "_fs", buffer_size),
|
||||||
Buffer::CreateSharedBuffer(name + "_fs", buffer_size),
|
false /*buffer_has_data*/),
|
||||||
false /*buffer_has_data*/),
|
for_client(Buffer::CreateSharedBuffer(name + "_fc", buffer_size),
|
||||||
for_client(
|
true /*buffer_has_data*/) {}
|
||||||
Buffer::CreateSharedBuffer(name + "_fc", buffer_size),
|
|
||||||
true /*buffer_has_data*/) {}
|
|
||||||
|
|
||||||
void RegisterId(TId id,
|
void RegisterId(TId id,
|
||||||
const Serializer& serializer,
|
const Serializer& serializer,
|
||||||
@ -42,7 +40,8 @@ struct TypedBidiMessageQueue {
|
|||||||
writer.SetIndent(' ', 0);
|
writer.SetIndent(' ', 0);
|
||||||
|
|
||||||
// Serialize the message.
|
// Serialize the message.
|
||||||
assert(serializers_.find(id) != serializers_.end() && "No registered serializer");
|
assert(serializers_.find(id) != serializers_.end() &&
|
||||||
|
"No registered serializer");
|
||||||
const Serializer& serializer = serializers_.find(id)->second;
|
const Serializer& serializer = serializers_.find(id)->second;
|
||||||
serializer(writer, message);
|
serializer(writer, message);
|
||||||
|
|
||||||
|
148
src/utils.cc
148
src/utils.cc
@ -7,25 +7,29 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|
||||||
#if !defined(__APPLE__)
|
#if !defined(__APPLE__)
|
||||||
#include <sparsepp/spp_memory.h>
|
#include <sparsepp/spp_memory.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// See http://stackoverflow.com/a/217605
|
// See http://stackoverflow.com/a/217605
|
||||||
void TrimStart(std::string& s) {
|
void TrimStart(std::string& s) {
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
|
s.erase(s.begin(),
|
||||||
std::not1(std::ptr_fun<int, int>(std::isspace))));
|
std::find_if(s.begin(), s.end(),
|
||||||
|
std::not1(std::ptr_fun<int, int>(std::isspace))));
|
||||||
}
|
}
|
||||||
void TrimEnd(std::string& s) {
|
void TrimEnd(std::string& s) {
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(),
|
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||||
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
std::not1(std::ptr_fun<int, int>(std::isspace)))
|
||||||
|
.base(),
|
||||||
|
s.end());
|
||||||
}
|
}
|
||||||
void Trim(std::string& s) {
|
void Trim(std::string& s) {
|
||||||
TrimStart(s);
|
TrimStart(s);
|
||||||
@ -45,20 +49,24 @@ bool StartsWith(const std::string& value, const std::string& start) {
|
|||||||
return std::equal(start.begin(), start.end(), value.begin());
|
return std::equal(start.begin(), start.end(), value.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnyStartsWith(const std::vector<std::string>& values, const std::string& start) {
|
bool AnyStartsWith(const std::vector<std::string>& values,
|
||||||
return std::any_of(std::begin(values), std::end(values), [&start](const std::string& value) {
|
const std::string& start) {
|
||||||
return StartsWith(value, start);
|
return std::any_of(
|
||||||
});
|
std::begin(values), std::end(values),
|
||||||
|
[&start](const std::string& value) { return StartsWith(value, start); });
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EndsWithAny(const std::string& value, const std::vector<std::string>& endings) {
|
bool EndsWithAny(const std::string& value,
|
||||||
return std::any_of(std::begin(endings), std::end(endings), [&value](const std::string& ending) {
|
const std::vector<std::string>& endings) {
|
||||||
return EndsWith(value, ending);
|
return std::any_of(
|
||||||
});
|
std::begin(endings), std::end(endings),
|
||||||
|
[&value](const std::string& ending) { return EndsWith(value, ending); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// See http://stackoverflow.com/a/29752943
|
// See http://stackoverflow.com/a/29752943
|
||||||
std::string ReplaceAll(const std::string& source, const std::string& from, const std::string& to) {
|
std::string ReplaceAll(const std::string& source,
|
||||||
|
const std::string& from,
|
||||||
|
const std::string& to) {
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(source.length()); // avoids a few memory allocations
|
result.reserve(source.length()); // avoids a few memory allocations
|
||||||
|
|
||||||
@ -77,7 +85,8 @@ std::string ReplaceAll(const std::string& source, const std::string& from, const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// http://stackoverflow.com/a/13172514
|
||||||
std::vector<std::string> strings;
|
std::vector<std::string> strings;
|
||||||
|
|
||||||
@ -104,17 +113,20 @@ std::string LowerPathIfCaseInsensitive(const std::string& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void GetFilesInFolderHelper(
|
static void GetFilesInFolderHelper(
|
||||||
std::string folder, bool recursive, std::string output_prefix, const std::function<void(const std::string&)>& handler) {
|
std::string folder,
|
||||||
|
bool recursive,
|
||||||
|
std::string output_prefix,
|
||||||
|
const std::function<void(const std::string&)>& handler) {
|
||||||
tinydir_dir dir;
|
tinydir_dir dir;
|
||||||
if (tinydir_open(&dir, folder.c_str()) == -1) {
|
if (tinydir_open(&dir, folder.c_str()) == -1) {
|
||||||
//perror("Error opening file");
|
// perror("Error opening file");
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (dir.has_next) {
|
while (dir.has_next) {
|
||||||
tinydir_file file;
|
tinydir_file file;
|
||||||
if (tinydir_readfile(&dir, &file) == -1) {
|
if (tinydir_readfile(&dir, &file) == -1) {
|
||||||
//perror("Error getting file");
|
// perror("Error getting file");
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,10 +139,10 @@ static void GetFilesInFolderHelper(
|
|||||||
if (recursive) {
|
if (recursive) {
|
||||||
std::string child_dir = output_prefix + file.name + "/";
|
std::string child_dir = output_prefix + file.name + "/";
|
||||||
if (!IsSymLink(child_dir))
|
if (!IsSymLink(child_dir))
|
||||||
GetFilesInFolderHelper(file.path, true /*recursive*/, child_dir, handler);
|
GetFilesInFolderHelper(file.path, true /*recursive*/, child_dir,
|
||||||
|
handler);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
handler(output_prefix + file.name);
|
handler(output_prefix + file.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,19 +157,24 @@ bail:
|
|||||||
tinydir_close(&dir);
|
tinydir_close(&dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> GetFilesInFolder(std::string folder, bool recursive, bool add_folder_to_path) {
|
std::vector<std::string> GetFilesInFolder(std::string folder,
|
||||||
|
bool recursive,
|
||||||
|
bool add_folder_to_path) {
|
||||||
EnsureEndsInSlash(folder);
|
EnsureEndsInSlash(folder);
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
GetFilesInFolderHelper(folder, recursive, add_folder_to_path ? folder : "", [&result](const std::string& path) {
|
GetFilesInFolderHelper(
|
||||||
result.push_back(path);
|
folder, recursive, add_folder_to_path ? folder : "",
|
||||||
});
|
[&result](const std::string& path) { result.push_back(path); });
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetFilesInFolder(std::string folder,
|
||||||
void GetFilesInFolder(std::string folder, bool recursive, bool add_folder_to_path, const std::function<void(const std::string&)>& handler) {
|
bool recursive,
|
||||||
|
bool add_folder_to_path,
|
||||||
|
const std::function<void(const std::string&)>& handler) {
|
||||||
EnsureEndsInSlash(folder);
|
EnsureEndsInSlash(folder);
|
||||||
GetFilesInFolderHelper(folder, recursive, add_folder_to_path ? folder : "", handler);
|
GetFilesInFolderHelper(folder, recursive, add_folder_to_path ? folder : "",
|
||||||
|
handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnsureEndsInSlash(std::string& path) {
|
void EnsureEndsInSlash(std::string& path) {
|
||||||
@ -165,38 +182,37 @@ void EnsureEndsInSlash(std::string& path) {
|
|||||||
path += '/';
|
path += '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// http://stackoverflow.com/a/6089413
|
// http://stackoverflow.com/a/6089413
|
||||||
std::istream& SafeGetline(std::istream& is, std::string& t) {
|
std::istream& SafeGetline(std::istream& is, std::string& t) {
|
||||||
t.clear();
|
t.clear();
|
||||||
|
|
||||||
// The characters in the stream are read one-by-one using a std::streambuf.
|
// The characters in the stream are read one-by-one using a std::streambuf.
|
||||||
// That is faster than reading them one-by-one using the std::istream.
|
// That is faster than reading them one-by-one using the std::istream.
|
||||||
// Code that uses streambuf this way must be guarded by a sentry object.
|
// Code that uses streambuf this way must be guarded by a sentry object.
|
||||||
// The sentry object performs various tasks,
|
// The sentry object performs various tasks,
|
||||||
// such as thread synchronization and updating the stream state.
|
// such as thread synchronization and updating the stream state.
|
||||||
|
|
||||||
std::istream::sentry se(is, true);
|
std::istream::sentry se(is, true);
|
||||||
std::streambuf* sb = is.rdbuf();
|
std::streambuf* sb = is.rdbuf();
|
||||||
|
|
||||||
for(;;) {
|
for (;;) {
|
||||||
int c = sb->sbumpc();
|
int c = sb->sbumpc();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '\n':
|
case '\n':
|
||||||
return is;
|
return is;
|
||||||
case '\r':
|
case '\r':
|
||||||
if(sb->sgetc() == '\n')
|
if (sb->sgetc() == '\n')
|
||||||
sb->sbumpc();
|
sb->sbumpc();
|
||||||
return is;
|
return is;
|
||||||
case EOF:
|
case EOF:
|
||||||
// Also handle the case when the last line has no line ending
|
// Also handle the case when the last line has no line ending
|
||||||
if(t.empty())
|
if (t.empty())
|
||||||
is.setstate(std::ios::eofbit);
|
is.setstate(std::ios::eofbit);
|
||||||
return is;
|
return is;
|
||||||
default:
|
default:
|
||||||
t += (char)c;
|
t += (char)c;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<std::string> ReadContent(const std::string& filename) {
|
optional<std::string> ReadContent(const std::string& filename) {
|
||||||
@ -205,22 +221,22 @@ optional<std::string> ReadContent(const std::string& filename) {
|
|||||||
if (!cache.good())
|
if (!cache.good())
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
return std::string(
|
return std::string(std::istreambuf_iterator<char>(cache),
|
||||||
std::istreambuf_iterator<char>(cache),
|
std::istreambuf_iterator<char>());
|
||||||
std::istreambuf_iterator<char>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ReadLines(std::string filename) {
|
std::vector<std::string> ReadLines(std::string filename) {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
std::ifstream input(filename);
|
std::ifstream input(filename);
|
||||||
for (std::string line; SafeGetline(input, line); )
|
for (std::string line; SafeGetline(input, line);)
|
||||||
result.push_back(line);
|
result.push_back(line);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ToLines(const std::string& content, bool trim_whitespace) {
|
std::vector<std::string> ToLines(const std::string& content,
|
||||||
|
bool trim_whitespace) {
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
|
||||||
std::istringstream lines(content);
|
std::istringstream lines(content);
|
||||||
@ -235,11 +251,12 @@ std::vector<std::string> ToLines(const std::string& content, bool trim_whitespac
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> ParseTestExpectation(std::string filename) {
|
std::unordered_map<std::string, std::string> ParseTestExpectation(
|
||||||
|
std::string filename) {
|
||||||
bool in_output = false;
|
bool in_output = false;
|
||||||
|
|
||||||
#if false
|
#if false
|
||||||
#include "bar.h"
|
#include "bar.h"
|
||||||
|
|
||||||
void foo();
|
void foo();
|
||||||
|
|
||||||
@ -275,8 +292,7 @@ std::unordered_map<std::string, std::string> ParseTestExpectation(std::string fi
|
|||||||
active_output_contents = "";
|
active_output_contents = "";
|
||||||
|
|
||||||
in_output = true;
|
in_output = true;
|
||||||
}
|
} else if (in_output)
|
||||||
else if (in_output)
|
|
||||||
active_output_contents += line + "\n";
|
active_output_contents += line + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,11 +301,14 @@ std::unordered_map<std::string, std::string> ParseTestExpectation(std::string fi
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
// Read the entire file into a string.
|
||||||
std::ifstream in(filename);
|
std::ifstream in(filename);
|
||||||
std::string str;
|
std::string str;
|
||||||
str.assign(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>());
|
str.assign(std::istreambuf_iterator<char>(in),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
in.close();
|
in.close();
|
||||||
|
|
||||||
// Replace expectation
|
// Replace expectation
|
||||||
@ -333,4 +352,3 @@ std::string FormatMicroseconds(long long microseconds) {
|
|||||||
|
|
||||||
return std::to_string(milliseconds) + "." + std::to_string(remaining) + "ms";
|
return std::to_string(milliseconds) + "." + std::to_string(remaining) + "ms";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
106
src/utils.h
106
src/utils.h
@ -10,8 +10,8 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
// Trim from start (in place)
|
// Trim from start (in place)
|
||||||
void TrimStart(std::string& s);
|
void TrimStart(std::string& s);
|
||||||
@ -23,16 +23,20 @@ void Trim(std::string& s);
|
|||||||
// Returns true if |value| starts/ends with |start| or |ending|.
|
// Returns true if |value| starts/ends with |start| or |ending|.
|
||||||
bool StartsWith(const std::string& value, const std::string& start);
|
bool StartsWith(const std::string& value, const std::string& start);
|
||||||
bool EndsWith(const std::string& value, const std::string& ending);
|
bool EndsWith(const std::string& value, const std::string& ending);
|
||||||
bool AnyStartsWith(const std::vector<std::string>& values, const std::string& start);
|
bool AnyStartsWith(const std::vector<std::string>& values,
|
||||||
bool EndsWithAny(const std::string& value, const std::vector<std::string>& endings);
|
const std::string& start);
|
||||||
|
bool EndsWithAny(const std::string& value,
|
||||||
|
const std::vector<std::string>& endings);
|
||||||
|
|
||||||
std::string ReplaceAll(const std::string& source, const std::string& from, const std::string& to);
|
std::string ReplaceAll(const std::string& source,
|
||||||
|
const std::string& from,
|
||||||
|
const std::string& to);
|
||||||
|
|
||||||
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 LowerPathIfCaseInsensitive(const std::string& path);
|
std::string LowerPathIfCaseInsensitive(const std::string& path);
|
||||||
|
|
||||||
|
|
||||||
template <typename TValues, typename TMap>
|
template <typename TValues, typename TMap>
|
||||||
std::string StringJoinMap(const TValues& values, const TMap& map) {
|
std::string StringJoinMap(const TValues& values, const TMap& map) {
|
||||||
std::string result;
|
std::string result;
|
||||||
@ -48,56 +52,66 @@ std::string StringJoinMap(const TValues& values, const TMap& map) {
|
|||||||
|
|
||||||
template <typename TValues>
|
template <typename TValues>
|
||||||
std::string StringJoin(const TValues& values) {
|
std::string StringJoin(const TValues& values) {
|
||||||
return StringJoinMap(values, [](const std::string& entry) {
|
return StringJoinMap(values, [](const std::string& entry) { return entry; });
|
||||||
return entry;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finds all files in the given folder. This is recursive.
|
// Finds all files in the given folder. This is recursive.
|
||||||
std::vector<std::string> GetFilesInFolder(std::string folder, bool recursive, bool add_folder_to_path);
|
std::vector<std::string> GetFilesInFolder(std::string folder,
|
||||||
void GetFilesInFolder(std::string folder, bool recursive, bool add_folder_to_path, const std::function<void(const std::string&)>& handler);
|
bool recursive,
|
||||||
|
bool add_folder_to_path);
|
||||||
|
void GetFilesInFolder(std::string folder,
|
||||||
|
bool recursive,
|
||||||
|
bool add_folder_to_path,
|
||||||
|
const std::function<void(const std::string&)>& handler);
|
||||||
|
|
||||||
// Ensures that |path| ends in a slash.
|
// Ensures that |path| ends in a slash.
|
||||||
void EnsureEndsInSlash(std::string& path);
|
void EnsureEndsInSlash(std::string& path);
|
||||||
|
|
||||||
optional<std::string> ReadContent(const std::string& filename);
|
optional<std::string> ReadContent(const std::string& filename);
|
||||||
std::vector<std::string> ReadLines(std::string filename);
|
std::vector<std::string> ReadLines(std::string filename);
|
||||||
std::vector<std::string> ToLines(const std::string& content, bool trim_whitespace);
|
std::vector<std::string> ToLines(const std::string& content,
|
||||||
|
bool trim_whitespace);
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> ParseTestExpectation(
|
||||||
std::unordered_map<std::string, std::string> ParseTestExpectation(std::string filename);
|
std::string filename);
|
||||||
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);
|
||||||
|
|
||||||
void Fail(const std::string& message);
|
void Fail(const std::string& message);
|
||||||
|
|
||||||
|
|
||||||
void WriteToFile(const std::string& filename, const std::string& content);
|
void WriteToFile(const std::string& filename, const std::string& content);
|
||||||
|
|
||||||
// note: this implementation does not disable this overload for array types
|
// note: this implementation does not disable this overload for array types
|
||||||
// See http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique#Possible_Implementatiog
|
// See
|
||||||
template<typename T, typename... Args>
|
// http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique#Possible_Implementatiog
|
||||||
|
template <typename T, typename... Args>
|
||||||
std::unique_ptr<T> MakeUnique(Args&&... args) {
|
std::unique_ptr<T> MakeUnique(Args&&... args) {
|
||||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void AddRange(std::vector<T>* dest, const std::vector<T>& to_add) {
|
void AddRange(std::vector<T>* dest, const std::vector<T>& to_add) {
|
||||||
for (const T& e : to_add)
|
for (const T& e : to_add)
|
||||||
dest->push_back(e);
|
dest->push_back(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void PushRange(std::queue<T>* dest, const std::vector<T>& to_add) {
|
void PushRange(std::queue<T>* dest, const std::vector<T>& to_add) {
|
||||||
for (const T& e : to_add)
|
for (const T& e : to_add)
|
||||||
dest->push(e);
|
dest->push(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
|
void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
|
||||||
dest->erase(std::remove_if(dest->begin(), dest->end(), [&](const T& t) {
|
dest->erase(std::remove_if(dest->begin(), dest->end(),
|
||||||
// TODO: make to_remove a set?
|
[&](const T& t) {
|
||||||
return std::find(to_remove.begin(), to_remove.end(), t) != to_remove.end();
|
// TODO: make to_remove a set?
|
||||||
}), dest->end());
|
return std::find(to_remove.begin(),
|
||||||
|
to_remove.end(),
|
||||||
|
t) != to_remove.end();
|
||||||
|
}),
|
||||||
|
dest->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://stackoverflow.com/a/38140932
|
// http://stackoverflow.com/a/38140932
|
||||||
@ -109,7 +123,7 @@ void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) {
|
|||||||
// };
|
// };
|
||||||
// MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)
|
// MAKE_HASHABLE(SomeHashKey, t.key1, t.key2, t.key3)
|
||||||
|
|
||||||
inline void hash_combine(std::size_t& seed) { }
|
inline void hash_combine(std::size_t& seed) {}
|
||||||
|
|
||||||
template <typename T, typename... Rest>
|
template <typename T, typename... Rest>
|
||||||
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
||||||
@ -118,25 +132,27 @@ inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
|||||||
hash_combine(seed, rest...);
|
hash_combine(seed, rest...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAKE_HASHABLE(type, ...) \
|
#define MAKE_HASHABLE(type, ...) \
|
||||||
namespace std {\
|
namespace std { \
|
||||||
template<> struct hash<type> {\
|
template <> \
|
||||||
std::size_t operator()(const type &t) const {\
|
struct hash<type> { \
|
||||||
std::size_t ret = 0;\
|
std::size_t operator()(const type& t) const { \
|
||||||
hash_combine(ret, __VA_ARGS__);\
|
std::size_t ret = 0; \
|
||||||
return ret;\
|
hash_combine(ret, __VA_ARGS__); \
|
||||||
}\
|
return ret; \
|
||||||
};\
|
} \
|
||||||
}
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
#define MAKE_ENUM_HASHABLE(type) \
|
#define MAKE_ENUM_HASHABLE(type) \
|
||||||
namespace std {\
|
namespace std { \
|
||||||
template<> struct hash<type> {\
|
template <> \
|
||||||
std::size_t operator()(const type &t) const {\
|
struct hash<type> { \
|
||||||
return hash<int>()(static_cast<int>(t));\
|
std::size_t operator()(const type& t) const { \
|
||||||
}\
|
return hash<int>()(static_cast<int>(t)); \
|
||||||
};\
|
} \
|
||||||
}
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
float GetProcessMemoryUsedInMb();
|
float GetProcessMemoryUsedInMb();
|
||||||
|
|
||||||
|
@ -6,9 +6,8 @@ std::atomic<int> WorkThread::num_active_threads;
|
|||||||
std::atomic<bool> WorkThread::request_exit_on_idle;
|
std::atomic<bool> WorkThread::request_exit_on_idle;
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void WorkThread::StartThread(
|
void WorkThread::StartThread(const std::string& thread_name,
|
||||||
const std::string& thread_name,
|
const std::function<Result()>& entry_point) {
|
||||||
const std::function<Result()>& entry_point) {
|
|
||||||
new std::thread([thread_name, entry_point]() {
|
new std::thread([thread_name, entry_point]() {
|
||||||
SetCurrentThreadName(thread_name);
|
SetCurrentThreadName(thread_name);
|
||||||
|
|
||||||
|
@ -9,11 +9,7 @@
|
|||||||
// Helper methods for starting threads that do some work. Enables test code to
|
// Helper methods for starting threads that do some work. Enables test code to
|
||||||
// wait for all work to complete.
|
// wait for all work to complete.
|
||||||
struct WorkThread {
|
struct WorkThread {
|
||||||
enum class Result {
|
enum class Result { MoreWork, NoWork, ExitThread };
|
||||||
MoreWork,
|
|
||||||
NoWork,
|
|
||||||
ExitThread
|
|
||||||
};
|
|
||||||
|
|
||||||
// The number of active worker threads.
|
// The number of active worker threads.
|
||||||
static std::atomic<int> num_active_threads;
|
static std::atomic<int> num_active_threads;
|
||||||
@ -22,9 +18,8 @@ struct WorkThread {
|
|||||||
|
|
||||||
// Launch a new thread. |entry_point| will be called continously. It should
|
// Launch a new thread. |entry_point| will be called continously. It should
|
||||||
// return true if it there is still known work to be done.
|
// return true if it there is still known work to be done.
|
||||||
static void StartThread(
|
static void StartThread(const std::string& thread_name,
|
||||||
const std::string& thread_name,
|
const std::function<Result()>& entry_point);
|
||||||
const std::function<Result()>& entry_point);
|
|
||||||
|
|
||||||
// Static-only class.
|
// Static-only class.
|
||||||
WorkThread() = delete;
|
WorkThread() = delete;
|
||||||
|
@ -19,8 +19,7 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
|
|||||||
if (content[i] == '\n') {
|
if (content[i] == '\n') {
|
||||||
result.line += 1;
|
result.line += 1;
|
||||||
result.character = 0;
|
result.character = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
result.character += 1;
|
result.character += 1;
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
@ -31,9 +30,8 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
|
|||||||
|
|
||||||
} // 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) {
|
: filename(filename), buffer_content(buffer_content) {
|
||||||
OnBufferContentUpdated();
|
OnBufferContentUpdated();
|
||||||
|
|
||||||
@ -51,7 +49,7 @@ void WorkingFile::SetIndexContent(const std::string& index_content) {
|
|||||||
|
|
||||||
auto it = index_lines_lookup.find(index_line);
|
auto it = index_lines_lookup.find(index_line);
|
||||||
if (it == index_lines_lookup.end())
|
if (it == index_lines_lookup.end())
|
||||||
index_lines_lookup[index_line] = { i + 1 };
|
index_lines_lookup[index_line] = {i + 1};
|
||||||
else
|
else
|
||||||
it->second.push_back(i + 1);
|
it->second.push_back(i + 1);
|
||||||
}
|
}
|
||||||
@ -68,7 +66,7 @@ void WorkingFile::OnBufferContentUpdated() {
|
|||||||
|
|
||||||
auto it = all_buffer_lines_lookup.find(buffer_line);
|
auto it = all_buffer_lines_lookup.find(buffer_line);
|
||||||
if (it == all_buffer_lines_lookup.end())
|
if (it == all_buffer_lines_lookup.end())
|
||||||
all_buffer_lines_lookup[buffer_line] = { i + 1 };
|
all_buffer_lines_lookup[buffer_line] = {i + 1};
|
||||||
else
|
else
|
||||||
it->second.push_back(i + 1);
|
it->second.push_back(i + 1);
|
||||||
}
|
}
|
||||||
@ -86,14 +84,15 @@ optional<int> WorkingFile::GetBufferLineFromIndexLine(int index_line) const {
|
|||||||
// Note: |index_line| and |buffer_line| are 1-based.
|
// Note: |index_line| and |buffer_line| are 1-based.
|
||||||
|
|
||||||
// TODO: reenable this assert once we are using the real indexed file.
|
// TODO: reenable this assert once we are using the real indexed file.
|
||||||
//assert(index_line >= 1 && index_line <= index_lines.size());
|
// assert(index_line >= 1 && index_line <= index_lines.size());
|
||||||
if (index_line < 1 || index_line > index_lines.size()) {
|
if (index_line < 1 || index_line > index_lines.size()) {
|
||||||
std::cerr << "!! Bad index_line (got " << index_line << ", expected [1, " << index_lines.size() << "])" << std::endl;
|
std::cerr << "!! Bad index_line (got " << index_line << ", expected [1, "
|
||||||
|
<< index_lines.size() << "])" << std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the line in the cached index file. We'll try to find the most similar line
|
// Find the line in the cached index file. We'll try to find the most similar
|
||||||
// in the buffer and return the index for that.
|
// line in the buffer and return the index for that.
|
||||||
std::string index = index_lines[index_line - 1];
|
std::string index = index_lines[index_line - 1];
|
||||||
auto buffer_it = all_buffer_lines_lookup.find(index);
|
auto buffer_it = all_buffer_lines_lookup.find(index);
|
||||||
if (buffer_it == all_buffer_lines_lookup.end()) {
|
if (buffer_it == all_buffer_lines_lookup.end()) {
|
||||||
@ -122,9 +121,10 @@ optional<int> WorkingFile::GetIndexLineFromBufferLine(int buffer_line) const {
|
|||||||
// See GetBufferLineFromIndexLine for additional comments.
|
// See GetBufferLineFromIndexLine for additional comments.
|
||||||
|
|
||||||
// Note: |index_line| and |buffer_line| are 1-based.
|
// Note: |index_line| and |buffer_line| are 1-based.
|
||||||
//assert(buffer_line >= 1 && buffer_line < all_buffer_lines.size());
|
// assert(buffer_line >= 1 && buffer_line < all_buffer_lines.size());
|
||||||
if (buffer_line < 1 || buffer_line > all_buffer_lines.size()) {
|
if (buffer_line < 1 || buffer_line > all_buffer_lines.size()) {
|
||||||
std::cerr << "!! Bad buffer_line (got " << buffer_line << ", expected [1, " << all_buffer_lines.size() << "])" << std::endl;
|
std::cerr << "!! Bad buffer_line (got " << buffer_line << ", expected [1, "
|
||||||
|
<< all_buffer_lines.size() << "])" << std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +154,9 @@ optional<int> WorkingFile::GetIndexLineFromBufferLine(int buffer_line) const {
|
|||||||
return closest_index_line;
|
return closest_index_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<std::string> WorkingFile::GetBufferLineContentFromIndexLine(int indexed_line, optional<int>* out_buffer_line) const {
|
optional<std::string> WorkingFile::GetBufferLineContentFromIndexLine(
|
||||||
|
int indexed_line,
|
||||||
|
optional<int>* out_buffer_line) const {
|
||||||
optional<int> buffer_line = GetBufferLineFromIndexLine(indexed_line);
|
optional<int> buffer_line = GetBufferLineFromIndexLine(indexed_line);
|
||||||
if (out_buffer_line)
|
if (out_buffer_line)
|
||||||
*out_buffer_line = buffer_line;
|
*out_buffer_line = buffer_line;
|
||||||
@ -163,14 +165,19 @@ optional<std::string> WorkingFile::GetBufferLineContentFromIndexLine(int indexed
|
|||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
if (*buffer_line < 1 || *buffer_line >= all_buffer_lines.size()) {
|
if (*buffer_line < 1 || *buffer_line >= all_buffer_lines.size()) {
|
||||||
std::cerr << "GetBufferLineContentFromIndexLine buffer line lookup not in all_buffer_lines" << std::endl;
|
std::cerr << "GetBufferLineContentFromIndexLine buffer line lookup not in "
|
||||||
|
"all_buffer_lines"
|
||||||
|
<< std::endl;
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
return all_buffer_lines[*buffer_line - 1];
|
return all_buffer_lines[*buffer_line - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* active_parameter, lsPosition* completion_position) const {
|
std::string WorkingFile::FindClosestCallNameInBuffer(
|
||||||
|
lsPosition position,
|
||||||
|
int* active_parameter,
|
||||||
|
lsPosition* completion_position) const {
|
||||||
*active_parameter = 0;
|
*active_parameter = 0;
|
||||||
|
|
||||||
int offset = GetOffsetForPosition(position, buffer_content);
|
int offset = GetOffsetForPosition(position, buffer_content);
|
||||||
@ -184,8 +191,10 @@ std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* a
|
|||||||
int balance = 0;
|
int balance = 0;
|
||||||
while (offset > 0) {
|
while (offset > 0) {
|
||||||
char c = buffer_content[offset];
|
char c = buffer_content[offset];
|
||||||
if (c == ')') ++balance;
|
if (c == ')')
|
||||||
else if (c == '(') --balance;
|
++balance;
|
||||||
|
else if (c == '(')
|
||||||
|
--balance;
|
||||||
|
|
||||||
if (balance == 0 && c == ',')
|
if (balance == 0 && c == ',')
|
||||||
*active_parameter += 1;
|
*active_parameter += 1;
|
||||||
@ -214,7 +223,10 @@ std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* a
|
|||||||
return buffer_content.substr(offset, start_offset - offset + 1);
|
return buffer_content.substr(offset, start_offset - offset + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
lsPosition WorkingFile::FindStableCompletionSource(lsPosition position, bool* is_global_completion, std::string* existing_completion) const {
|
lsPosition WorkingFile::FindStableCompletionSource(
|
||||||
|
lsPosition position,
|
||||||
|
bool* is_global_completion,
|
||||||
|
std::string* existing_completion) const {
|
||||||
*is_global_completion = true;
|
*is_global_completion = true;
|
||||||
|
|
||||||
int start_offset = GetOffsetForPosition(position, buffer_content);
|
int start_offset = GetOffsetForPosition(position, buffer_content);
|
||||||
@ -257,7 +269,8 @@ WorkingFile* WorkingFiles::GetFileByFilename(const std::string& filename) {
|
|||||||
return GetFileByFilenameNoLock(filename);
|
return GetFileByFilenameNoLock(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkingFile* WorkingFiles::GetFileByFilenameNoLock(const std::string& filename) {
|
WorkingFile* WorkingFiles::GetFileByFilenameNoLock(
|
||||||
|
const std::string& filename) {
|
||||||
for (auto& file : files) {
|
for (auto& file : files) {
|
||||||
if (file->filename == filename)
|
if (file->filename == filename)
|
||||||
return file.get();
|
return file.get();
|
||||||
@ -273,7 +286,6 @@ void WorkingFiles::DoAction(const std::function<void()>& action) {
|
|||||||
void WorkingFiles::DoActionOnFile(
|
void WorkingFiles::DoActionOnFile(
|
||||||
const std::string& filename,
|
const std::string& filename,
|
||||||
const std::function<void(WorkingFile* file)>& action) {
|
const std::function<void(WorkingFile* file)>& action) {
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(files_mutex);
|
std::lock_guard<std::mutex> lock(files_mutex);
|
||||||
WorkingFile* file = GetFileByFilenameNoLock(filename);
|
WorkingFile* file = GetFileByFilenameNoLock(filename);
|
||||||
action(file);
|
action(file);
|
||||||
@ -303,28 +315,33 @@ void WorkingFiles::OnChange(const Ipc_TextDocumentDidChange::Params& change) {
|
|||||||
std::string filename = change.textDocument.uri.GetPath();
|
std::string filename = change.textDocument.uri.GetPath();
|
||||||
WorkingFile* file = GetFileByFilenameNoLock(filename);
|
WorkingFile* file = GetFileByFilenameNoLock(filename);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
std::cerr << "Could not change " << filename << " because it was not open" << std::endl;
|
std::cerr << "Could not change " << filename << " because it was not open"
|
||||||
|
<< std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file->version = change.textDocument.version;
|
file->version = change.textDocument.version;
|
||||||
// std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
|
// std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
|
||||||
//std::cerr << "VERSION " << change.textDocument.version << std::endl;
|
// std::cerr << "VERSION " << change.textDocument.version << std::endl;
|
||||||
|
|
||||||
for (const Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
|
for (const Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent& diff :
|
||||||
|
change.contentChanges) {
|
||||||
// std::cerr << "|" << file->buffer_content << "|" << std::endl;
|
// std::cerr << "|" << file->buffer_content << "|" << std::endl;
|
||||||
// If range or rangeLength are emitted we replace everything, per the spec.
|
// If range or rangeLength are emitted we replace everything, per the spec.
|
||||||
if (diff.rangeLength == -1) {
|
if (diff.rangeLength == -1) {
|
||||||
file->buffer_content = diff.text;
|
file->buffer_content = diff.text;
|
||||||
file->OnBufferContentUpdated();
|
file->OnBufferContentUpdated();
|
||||||
// std::cerr << "-> Replacing entire content";
|
// std::cerr << "-> Replacing entire content";
|
||||||
}
|
} else {
|
||||||
else {
|
int start_offset =
|
||||||
int start_offset = GetOffsetForPosition(diff.range.start, file->buffer_content);
|
GetOffsetForPosition(diff.range.start, file->buffer_content);
|
||||||
// std::cerr << "-> Applying diff start=" << diff.range.start.ToString() << ", end=" << diff.range.end.ToString() << ", start_offset=" << start_offset << std::endl;
|
// std::cerr << "-> Applying diff start=" << diff.range.start.ToString()
|
||||||
file->buffer_content.replace(file->buffer_content.begin() + start_offset,
|
// << ", end=" << diff.range.end.ToString() << ", start_offset=" <<
|
||||||
file->buffer_content.begin() + start_offset + diff.rangeLength,
|
// start_offset << std::endl;
|
||||||
diff.text);
|
file->buffer_content.replace(
|
||||||
|
file->buffer_content.begin() + start_offset,
|
||||||
|
file->buffer_content.begin() + start_offset + diff.rangeLength,
|
||||||
|
diff.text);
|
||||||
file->OnBufferContentUpdated();
|
file->OnBufferContentUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +349,8 @@ void WorkingFiles::OnChange(const Ipc_TextDocumentDidChange::Params& change) {
|
|||||||
}
|
}
|
||||||
// std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
|
// std::cerr << "!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
|
||||||
|
|
||||||
//std::cerr << std::endl << std::endl << "--------" << file->content << "--------" << std::endl << std::endl;
|
// std::cerr << std::endl << std::endl << "--------" << file->content <<
|
||||||
|
// "--------" << std::endl << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorkingFiles::OnClose(const Ipc_TextDocumentDidClose::Params& close) {
|
void WorkingFiles::OnClose(const Ipc_TextDocumentDidClose::Params& close) {
|
||||||
@ -347,7 +365,8 @@ void WorkingFiles::OnClose(const Ipc_TextDocumentDidClose::Params& close) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << "Could not close " << filename << " because it was not open" << std::endl;
|
std::cerr << "Could not close " << filename << " because it was not open"
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CXUnsavedFile> WorkingFiles::AsUnsavedFiles() {
|
std::vector<CXUnsavedFile> WorkingFiles::AsUnsavedFiles() {
|
||||||
@ -362,82 +381,108 @@ std::vector<CXUnsavedFile> WorkingFiles::AsUnsavedFiles() {
|
|||||||
|
|
||||||
TEST_SUITE("WorkingFile");
|
TEST_SUITE("WorkingFile");
|
||||||
|
|
||||||
lsPosition CharPos(const WorkingFile& file, char character, int character_offset = 0) {
|
lsPosition CharPos(const WorkingFile& file,
|
||||||
|
char character,
|
||||||
|
int character_offset = 0) {
|
||||||
return CharPos(file.buffer_content, character, character_offset);
|
return CharPos(file.buffer_content, character, character_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("simple call") {
|
TEST_CASE("simple call") {
|
||||||
WorkingFile f("foo.cc", "abcd(1, 2");
|
WorkingFile f("foo.cc", "abcd(1, 2");
|
||||||
int active_param = 0;
|
int active_param = 0;
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '('), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '('), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '1'), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '1'), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ','), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ','), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 1);
|
REQUIRE(active_param == 1);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ' '), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ' '), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 1);
|
REQUIRE(active_param == 1);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '2'), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '2'), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 1);
|
REQUIRE(active_param == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("nested call") {
|
TEST_CASE("nested call") {
|
||||||
WorkingFile f("foo.cc", "abcd(efg(), 2");
|
WorkingFile f("foo.cc", "abcd(efg(), 2");
|
||||||
int active_param = 0;
|
int active_param = 0;
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '('), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, '('), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'e'), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'e'), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'f'), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'f'), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'g'), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'g'), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'g', 1), &active_param) == "efg");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'g', 1), &active_param) ==
|
||||||
|
"efg");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'g', 2), &active_param) == "efg");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, 'g', 2), &active_param) ==
|
||||||
|
"efg");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ','), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ','), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 1);
|
REQUIRE(active_param == 1);
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ' '), &active_param) == "abcd");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ' '), &active_param) ==
|
||||||
|
"abcd");
|
||||||
REQUIRE(active_param == 1);
|
REQUIRE(active_param == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("auto-insert )") {
|
TEST_CASE("auto-insert )") {
|
||||||
WorkingFile f("foo.cc", "abc()");
|
WorkingFile f("foo.cc", "abc()");
|
||||||
int active_param = 0;
|
int active_param = 0;
|
||||||
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ')'), &active_param) == "abc");
|
REQUIRE(f.FindClosestCallNameInBuffer(CharPos(f, ')'), &active_param) ==
|
||||||
|
"abc");
|
||||||
REQUIRE(active_param == 0);
|
REQUIRE(active_param == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("existing completion") {
|
TEST_CASE("existing completion") {
|
||||||
// TODO: remove trailing space in zz.asdf. Lexing doesn't work correctly if done at the end of input.
|
// TODO: remove trailing space in zz.asdf. Lexing doesn't work correctly if
|
||||||
|
// done at the end of input.
|
||||||
WorkingFile f("foo.cc", "zzz.asdf ");
|
WorkingFile f("foo.cc", "zzz.asdf ");
|
||||||
bool is_global_completion;
|
bool is_global_completion;
|
||||||
std::string existing_completion;
|
std::string existing_completion;
|
||||||
|
|
||||||
f.FindStableCompletionSource(CharPos(f, '.'), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, '.'), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "zzz");
|
REQUIRE(existing_completion == "zzz");
|
||||||
f.FindStableCompletionSource(CharPos(f, 'a', 1), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, 'a', 1), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "a");
|
REQUIRE(existing_completion == "a");
|
||||||
f.FindStableCompletionSource(CharPos(f, 's', 1), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, 's', 1), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "as");
|
REQUIRE(existing_completion == "as");
|
||||||
f.FindStableCompletionSource(CharPos(f, 'd', 1), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, 'd', 1), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "asd");
|
REQUIRE(existing_completion == "asd");
|
||||||
f.FindStableCompletionSource(CharPos(f, 'f', 1), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, 'f', 1), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "asdf");
|
REQUIRE(existing_completion == "asdf");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("existing completion underscore") {
|
TEST_CASE("existing completion underscore") {
|
||||||
// TODO: remove trailing space in ABC_DEF. Lexing doesn't work correctly if done at the end of input.
|
// TODO: remove trailing space in ABC_DEF. Lexing doesn't work correctly if
|
||||||
|
// done at the end of input.
|
||||||
WorkingFile f("foo.cc", "ABC_DEF ");
|
WorkingFile f("foo.cc", "ABC_DEF ");
|
||||||
bool is_global_completion;
|
bool is_global_completion;
|
||||||
std::string existing_completion;
|
std::string existing_completion;
|
||||||
|
|
||||||
f.FindStableCompletionSource(CharPos(f, 'C'), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, 'C'), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "AB");
|
REQUIRE(existing_completion == "AB");
|
||||||
f.FindStableCompletionSource(CharPos(f, '_'), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, '_'), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "ABC");
|
REQUIRE(existing_completion == "ABC");
|
||||||
f.FindStableCompletionSource(CharPos(f, 'D'), &is_global_completion, &existing_completion);
|
f.FindStableCompletionSource(CharPos(f, 'D'), &is_global_completion,
|
||||||
|
&existing_completion);
|
||||||
REQUIRE(existing_completion == "ABC_");
|
REQUIRE(existing_completion == "ABC_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using std::experimental::optional;
|
|
||||||
using std::experimental::nullopt;
|
using std::experimental::nullopt;
|
||||||
|
using std::experimental::optional;
|
||||||
|
|
||||||
struct WorkingFile {
|
struct WorkingFile {
|
||||||
int version = 0;
|
int version = 0;
|
||||||
@ -28,7 +28,8 @@ struct WorkingFile {
|
|||||||
// Note: The items in the value entry are 1-based liness.
|
// Note: The items in the value entry are 1-based liness.
|
||||||
std::unordered_map<std::string, std::vector<int>> all_buffer_lines_lookup;
|
std::unordered_map<std::string, std::vector<int>> all_buffer_lines_lookup;
|
||||||
// A set of diagnostics that have been reported for this file.
|
// A set of diagnostics that have been reported for this file.
|
||||||
// NOTE: _ is appended because it must be accessed under the WorkingFiles lock!
|
// NOTE: _ is appended because it must be accessed under the WorkingFiles
|
||||||
|
// lock!
|
||||||
std::vector<lsDiagnostic> diagnostics_;
|
std::vector<lsDiagnostic> diagnostics_;
|
||||||
|
|
||||||
WorkingFile(const std::string& filename, const std::string& buffer_content);
|
WorkingFile(const std::string& filename, const std::string& buffer_content);
|
||||||
@ -45,16 +46,22 @@ struct WorkingFile {
|
|||||||
// accepts and returns 1-based lines.
|
// accepts and returns 1-based lines.
|
||||||
optional<int> GetIndexLineFromBufferLine(int buffer_line) const;
|
optional<int> GetIndexLineFromBufferLine(int buffer_line) const;
|
||||||
|
|
||||||
optional<std::string> GetBufferLineContentFromIndexLine(int indexed_line, optional<int>* out_buffer_line) const;
|
optional<std::string> GetBufferLineContentFromIndexLine(
|
||||||
|
int indexed_line,
|
||||||
|
optional<int>* out_buffer_line) const;
|
||||||
|
|
||||||
// TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into lex_utils.h/cc
|
// TODO: Move FindClosestCallNameInBuffer and FindStableCompletionSource into
|
||||||
|
// lex_utils.h/cc
|
||||||
|
|
||||||
// Finds the closest 'callable' name prior to position. This is used for
|
// Finds the closest 'callable' name prior to position. This is used for
|
||||||
// signature help to filter code completion results.
|
// signature help to filter code completion results.
|
||||||
//
|
//
|
||||||
// |completion_position| will be point to a good code completion location to
|
// |completion_position| will be point to a good code completion location to
|
||||||
// for fetching signatures.
|
// for fetching signatures.
|
||||||
std::string FindClosestCallNameInBuffer(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
|
// Returns a relatively stable completion position (it jumps back until there
|
||||||
// is a non-alphanumeric character).
|
// is a non-alphanumeric character).
|
||||||
@ -63,7 +70,9 @@ struct WorkingFile {
|
|||||||
// global completion.
|
// global completion.
|
||||||
// The out param |existing_completion| is set to any existing completion
|
// The out param |existing_completion| is set to any existing completion
|
||||||
// content the user has entered.
|
// content the user has entered.
|
||||||
lsPosition FindStableCompletionSource(lsPosition position, bool* is_global_completion, std::string* existing_completion) const;
|
lsPosition FindStableCompletionSource(lsPosition position,
|
||||||
|
bool* is_global_completion,
|
||||||
|
std::string* existing_completion) const;
|
||||||
|
|
||||||
CXUnsavedFile AsUnsavedFile() const;
|
CXUnsavedFile AsUnsavedFile() const;
|
||||||
};
|
};
|
||||||
@ -79,8 +88,10 @@ struct WorkingFiles {
|
|||||||
|
|
||||||
// Run |action| under the lock.
|
// Run |action| under the lock.
|
||||||
void DoAction(const std::function<void()>& action);
|
void DoAction(const std::function<void()>& action);
|
||||||
// Run |action| on the file identified by |filename|. This executes under the lock.
|
// Run |action| on the file identified by |filename|. This executes under the
|
||||||
void DoActionOnFile(const std::string& filename, const std::function<void(WorkingFile* file)>& action);
|
// lock.
|
||||||
|
void DoActionOnFile(const std::string& filename,
|
||||||
|
const std::function<void(WorkingFile* file)>& action);
|
||||||
|
|
||||||
WorkingFile* OnOpen(const Ipc_TextDocumentDidOpen::Params& open);
|
WorkingFile* OnOpen(const Ipc_TextDocumentDidOpen::Params& open);
|
||||||
void OnChange(const Ipc_TextDocumentDidChange::Params& change);
|
void OnChange(const Ipc_TextDocumentDidChange::Params& change);
|
||||||
@ -91,5 +102,5 @@ struct WorkingFiles {
|
|||||||
// Use unique_ptrs so we can handout WorkingFile ptrs and not have them
|
// Use unique_ptrs so we can handout WorkingFile ptrs and not have them
|
||||||
// invalidated if we resize files.
|
// invalidated if we resize files.
|
||||||
std::vector<std::unique_ptr<WorkingFile>> files;
|
std::vector<std::unique_ptr<WorkingFile>> files;
|
||||||
std::mutex files_mutex; // Protects |files|.
|
std::mutex files_mutex; // Protects |files|.
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user