mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-27 10:02:03 +00:00
Internalize strings & remove diagnostics_publisher.cc
This commit is contained in:
parent
c8a81aeae3
commit
e5d8153d4b
@ -193,7 +193,6 @@ target_sources(ccls PRIVATE
|
||||
src/clang_tu.cc
|
||||
src/clang_utils.cc
|
||||
src/config.cc
|
||||
src/diagnostics_publisher.cc
|
||||
src/file_consumer.cc
|
||||
src/filesystem.cc
|
||||
src/fuzzy_match.cc
|
||||
|
@ -259,7 +259,7 @@ std::string ClangCursor::get_type_description() const {
|
||||
return ::ToString(clang_getTypeSpelling(type));
|
||||
}
|
||||
|
||||
NtString ClangCursor::get_comments() const {
|
||||
std::string ClangCursor::get_comments() const {
|
||||
CXSourceRange range = clang_Cursor_getCommentRange(cx_cursor);
|
||||
if (clang_Range_isNull(range))
|
||||
return {};
|
||||
@ -317,7 +317,7 @@ NtString ClangCursor::get_comments() const {
|
||||
ret.pop_back();
|
||||
if (ret.empty())
|
||||
return {};
|
||||
return static_cast<std::string_view>(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string ClangCursor::ToString() const {
|
||||
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include "nt_string.h"
|
||||
#include "position.h"
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
@ -86,7 +85,7 @@ class ClangCursor {
|
||||
bool is_valid_kind() const;
|
||||
|
||||
std::string get_type_description() const;
|
||||
NtString get_comments() const;
|
||||
std::string get_comments() const;
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
#include "diagnostics_publisher.hh"
|
||||
|
||||
#include "pipeline.hh"
|
||||
using namespace ccls;
|
||||
|
||||
#include <chrono>
|
||||
|
||||
void DiagnosticsPublisher::Init() {
|
||||
frequencyMs_ = g_config->diagnostics.frequencyMs;
|
||||
match_ = std::make_unique<GroupMatch>(g_config->diagnostics.whitelist,
|
||||
g_config->diagnostics.blacklist);
|
||||
}
|
||||
|
||||
void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics) {
|
||||
// Cache diagnostics so we can show fixits.
|
||||
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
||||
if (working_file)
|
||||
working_file->diagnostics_ = diagnostics;
|
||||
});
|
||||
|
||||
int64_t now =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch())
|
||||
.count();
|
||||
if (frequencyMs_ >= 0 && (nextPublish_ <= now || diagnostics.empty()) &&
|
||||
match_->IsMatch(path)) {
|
||||
nextPublish_ = now + frequencyMs_;
|
||||
|
||||
Out_TextDocumentPublishDiagnostics out;
|
||||
out.params.uri = lsDocumentUri::FromPath(path);
|
||||
out.params.diagnostics = diagnostics;
|
||||
pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out);
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#include "lsp_diagnostic.h"
|
||||
|
||||
#include "match.h"
|
||||
#include "working_files.h"
|
||||
|
||||
class DiagnosticsPublisher {
|
||||
std::unique_ptr<GroupMatch> match_;
|
||||
int64_t nextPublish_ = 0;
|
||||
int frequencyMs_;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
void Publish(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics);
|
||||
};
|
@ -3,6 +3,7 @@
|
||||
#include "log.hh"
|
||||
#include "platform.h"
|
||||
#include "serializer.h"
|
||||
using ccls::Intern;
|
||||
|
||||
#include <clang/AST/AST.h>
|
||||
#include <clang/Frontend/ASTUnit.h>
|
||||
@ -523,8 +524,10 @@ void SetTypeName(IndexType& type,
|
||||
// ns {}` which are not qualified.
|
||||
// type->def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor);
|
||||
int short_name_offset, short_name_size;
|
||||
std::tie(type.def.detailed_name, short_name_offset, short_name_size) =
|
||||
std::string detailed;
|
||||
std::tie(detailed, short_name_offset, short_name_size) =
|
||||
param->ns.QualifiedName(container ? container : &parent, name);
|
||||
type.def.detailed_name = Intern(detailed);
|
||||
type.def.qual_name_offset = 0;
|
||||
type.def.short_name_offset = short_name_offset;
|
||||
type.def.short_name_size = short_name_size;
|
||||
@ -558,7 +561,7 @@ IndexType* ResolveToDeclarationType(IndexFile* db,
|
||||
if (!usr)
|
||||
return nullptr;
|
||||
IndexType& typ = db->ToType(*usr);
|
||||
if (typ.def.detailed_name.empty()) {
|
||||
if (!typ.def.detailed_name[0]) {
|
||||
std::string name = declaration.get_spell_name();
|
||||
SetTypeName(typ, declaration, nullptr, name.c_str(), param);
|
||||
}
|
||||
@ -580,7 +583,7 @@ void SetVarDetail(IndexVar& var,
|
||||
if (type_name.find("(lambda at") != std::string::npos)
|
||||
type_name = "lambda";
|
||||
if (g_config->index.comments)
|
||||
def.comments = cursor.get_comments();
|
||||
def.comments = Intern(cursor.get_comments());
|
||||
def.storage = GetStorageC(clang_Cursor_getStorageClass(cursor.cx_cursor));
|
||||
|
||||
// TODO how to make PrettyPrint'ed variable name qualified?
|
||||
@ -607,16 +610,16 @@ void SetVarDetail(IndexVar& var,
|
||||
else
|
||||
hover += std::to_string(TD->getInitVal().getSExtValue());
|
||||
}
|
||||
def.detailed_name = std::move(qualified_name);
|
||||
def.detailed_name = Intern(qualified_name);
|
||||
def.qual_name_offset = 0;
|
||||
def.hover = hover;
|
||||
def.hover = Intern(hover);
|
||||
} else {
|
||||
#if 0
|
||||
def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor, false);
|
||||
#else
|
||||
int offset = type_name.size();
|
||||
offset += ConcatTypeAndName(type_name, qualified_name);
|
||||
def.detailed_name = type_name;
|
||||
def.detailed_name = Intern(type_name);
|
||||
def.qual_name_offset = offset;
|
||||
def.short_name_offset += offset;
|
||||
// Append the textual initializer, bit field, constructor to |hover|.
|
||||
@ -663,8 +666,9 @@ void SetVarDetail(IndexVar& var,
|
||||
std::optional<int> spell_end = fc.ToOffset(spell_p),
|
||||
extent_end = fc.ToOffset(extent_p);
|
||||
if (extent_end && *spell_end < *extent_end)
|
||||
def.hover = std::string(def.detailed_name.c_str()) +
|
||||
fc.content.substr(*spell_end, *extent_end - *spell_end);
|
||||
def.hover =
|
||||
Intern(std::string(def.detailed_name) +
|
||||
fc.content.substr(*spell_end, *extent_end - *spell_end));
|
||||
}
|
||||
}
|
||||
skip:;
|
||||
@ -714,7 +718,7 @@ void OnIndexReference_Function(IndexFile* db,
|
||||
|
||||
// static
|
||||
const int IndexFile::kMajorVersion = 16;
|
||||
const int IndexFile::kMinorVersion = 0;
|
||||
const int IndexFile::kMinorVersion = 1;
|
||||
|
||||
IndexFile::IndexFile(const std::string& path, const std::string& contents)
|
||||
: path(path), file_contents(contents) {}
|
||||
@ -741,7 +745,7 @@ IndexVar& IndexFile::ToVar(Usr usr) {
|
||||
}
|
||||
|
||||
std::string IndexFile::ToString() {
|
||||
return Serialize(SerializeFormat::Json, *this);
|
||||
return ccls::Serialize(SerializeFormat::Json, *this);
|
||||
}
|
||||
|
||||
void Uniquify(std::vector<Usr>& usrs) {
|
||||
@ -1197,16 +1201,17 @@ ClangCursor::VisitResult VisitMacroDefinitionAndExpansions(ClangCursor cursor,
|
||||
IndexVar& var_def = db->ToVar(decl_usr);
|
||||
if (cursor.get_kind() == CXCursor_MacroDefinition) {
|
||||
CXSourceRange cx_extent = clang_getCursorExtent(cursor.cx_cursor);
|
||||
var_def.def.detailed_name = cursor.get_display_name();
|
||||
var_def.def.detailed_name = Intern(cursor.get_display_name());
|
||||
var_def.def.qual_name_offset = 0;
|
||||
var_def.def.short_name_offset = 0;
|
||||
var_def.def.short_name_size =
|
||||
int16_t(strlen(var_def.def.detailed_name.c_str()));
|
||||
int16_t(strlen(var_def.def.detailed_name));
|
||||
var_def.def.hover =
|
||||
"#define " + GetDocumentContentInRange(param->tu->cx_tu, cx_extent);
|
||||
Intern("#define " +
|
||||
GetDocumentContentInRange(param->tu->cx_tu, cx_extent));
|
||||
var_def.def.kind = lsSymbolKind::Macro;
|
||||
if (g_config->index.comments)
|
||||
var_def.def.comments = cursor.get_comments();
|
||||
var_def.def.comments = Intern(cursor.get_comments());
|
||||
var_def.def.spell =
|
||||
SetUse(db, decl_loc_spelling, parent, Role::Definition);
|
||||
var_def.def.extent = SetUse(
|
||||
@ -1244,7 +1249,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
|
||||
ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor);
|
||||
if (ref_cursor.get_kind() == CXCursor_NonTypeTemplateParameter) {
|
||||
IndexVar& ref_var = db->ToVar(ref_cursor);
|
||||
if (ref_var.def.detailed_name.empty()) {
|
||||
if (!ref_var.def.detailed_name[0]) {
|
||||
ClangCursor sem_parent = ref_cursor.get_semantic_parent();
|
||||
ClangCursor lex_parent = ref_cursor.get_lexical_parent();
|
||||
ref_var.def.spell =
|
||||
@ -1298,7 +1303,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
|
||||
// CXCursor_TemplateTemplateParameter can be visited by visiting
|
||||
// CXCursor_TranslationUnit, but not (confirm this) by visiting
|
||||
// {Class,Function}Template. Thus we need to initialize it here.
|
||||
if (ref_type.def.detailed_name.empty()) {
|
||||
if (!ref_type.def.detailed_name[0]) {
|
||||
ClangCursor sem_parent = ref_cursor.get_semantic_parent();
|
||||
ClangCursor lex_parent = ref_cursor.get_lexical_parent();
|
||||
ref_type.def.spell =
|
||||
@ -1308,11 +1313,11 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
|
||||
#if 0 && CINDEX_HAVE_PRETTY
|
||||
ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor);
|
||||
#else
|
||||
ref_type.def.detailed_name = ref_cursor.get_spell_name();
|
||||
ref_type.def.detailed_name = Intern(ref_cursor.get_spell_name());
|
||||
#endif
|
||||
ref_type.def.short_name_offset = 0;
|
||||
ref_type.def.short_name_size =
|
||||
int16_t(strlen(ref_type.def.detailed_name.c_str()));
|
||||
int16_t(strlen(ref_type.def.detailed_name));
|
||||
ref_type.def.kind = lsSymbolKind::TypeParameter;
|
||||
}
|
||||
AddUseSpell(db, ref_type.uses, cursor);
|
||||
@ -1328,7 +1333,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
|
||||
// CXCursor_TemplateTypeParameter can be visited by visiting
|
||||
// CXCursor_TranslationUnit, but not (confirm this) by visiting
|
||||
// {Class,Function}Template. Thus we need to initialize it here.
|
||||
if (ref_type.def.detailed_name.empty()) {
|
||||
if (!ref_type.def.detailed_name[0]) {
|
||||
ClangCursor sem_parent = ref_cursor.get_semantic_parent();
|
||||
ClangCursor lex_parent = ref_cursor.get_lexical_parent();
|
||||
ref_type.def.spell =
|
||||
@ -1339,11 +1344,11 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
|
||||
// template<class T> void f(T t){} // weird, the name is empty
|
||||
ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor);
|
||||
#else
|
||||
ref_type.def.detailed_name = ref_cursor.get_spell_name();
|
||||
ref_type.def.detailed_name = Intern(ref_cursor.get_spell_name());
|
||||
#endif
|
||||
ref_type.def.short_name_offset = 0;
|
||||
ref_type.def.short_name_size =
|
||||
int16_t(strlen(ref_type.def.detailed_name.c_str()));
|
||||
int16_t(strlen(ref_type.def.detailed_name));
|
||||
ref_type.def.kind = lsSymbolKind::TypeParameter;
|
||||
}
|
||||
AddUseSpell(db, ref_type.uses, cursor);
|
||||
@ -1443,7 +1448,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
Range spell = cursor.get_spell();
|
||||
IndexType& ns = db->ToType(HashUsr(decl->entityInfo->USR));
|
||||
ns.def.kind = GetSymbolKind(decl->entityInfo->kind);
|
||||
if (ns.def.detailed_name.empty()) {
|
||||
if (!ns.def.detailed_name[0]) {
|
||||
SetTypeName(ns, cursor, decl->semanticContainer, decl->entityInfo->name,
|
||||
param);
|
||||
ns.def.spell = SetUse(db, spell, sem_parent, Role::Definition);
|
||||
@ -1559,7 +1564,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
|
||||
IndexFunc& func = db->ToFunc(decl_cursor_resolved);
|
||||
if (g_config->index.comments)
|
||||
func.def.comments = cursor.get_comments();
|
||||
func.def.comments = Intern(cursor.get_comments());
|
||||
func.def.kind = GetSymbolKind(decl->entityInfo->kind);
|
||||
func.def.storage =
|
||||
GetStorageC(clang_Cursor_getStorageClass(decl->cursor));
|
||||
@ -1592,9 +1597,11 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
// indexing the definition, then there will not be any (ie) outline
|
||||
// information.
|
||||
if (!is_template_specialization) {
|
||||
std::tie(func.def.detailed_name, func.def.qual_name_offset,
|
||||
std::string detailed;
|
||||
std::tie(detailed, func.def.qual_name_offset,
|
||||
func.def.short_name_offset, func.def.short_name_size) =
|
||||
param->PrettyPrintCursor(decl->cursor, decl->entityInfo->name);
|
||||
func.def.detailed_name = Intern(detailed);
|
||||
|
||||
// CXCursor_OverloadedDeclRef in templates are not processed by
|
||||
// OnIndexReference, thus we use TemplateVisitor to collect function
|
||||
@ -1668,7 +1675,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
decl->entityInfo->name, param);
|
||||
type.def.kind = GetSymbolKind(decl->entityInfo->kind);
|
||||
if (g_config->index.comments)
|
||||
type.def.comments = cursor.get_comments();
|
||||
type.def.comments = Intern(cursor.get_comments());
|
||||
|
||||
// For Typedef/CXXTypeAlias spanning a few lines, display the declaration
|
||||
// line, with spelling name replaced with qualified name.
|
||||
@ -1679,10 +1686,10 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
spell_end = fc.ToOffset(spell.end),
|
||||
extent_end = fc.ToOffset(extent.end);
|
||||
if (extent_start && spell_start && spell_end && extent_end) {
|
||||
type.def.hover =
|
||||
type.def.hover = Intern(
|
||||
fc.content.substr(*extent_start, *spell_start - *extent_start) +
|
||||
type.def.detailed_name.c_str() +
|
||||
fc.content.substr(*spell_end, *extent_end - *spell_end);
|
||||
type.def.detailed_name +
|
||||
fc.content.substr(*spell_end, *extent_end - *spell_end));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1711,7 +1718,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
param);
|
||||
type.def.kind = GetSymbolKind(decl->entityInfo->kind);
|
||||
if (g_config->index.comments)
|
||||
type.def.comments = cursor.get_comments();
|
||||
type.def.comments = Intern(cursor.get_comments());
|
||||
// }
|
||||
|
||||
if (decl->isDefinition) {
|
||||
@ -1743,7 +1750,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
// template<class T> class function; // not visited by
|
||||
// OnIndexDeclaration template<> class function<int> {}; // current
|
||||
// cursor
|
||||
if (origin.def.detailed_name.empty()) {
|
||||
if (!origin.def.detailed_name[0]) {
|
||||
SetTypeName(origin, origin_cursor, nullptr,
|
||||
&type.def.Name(false)[0], param);
|
||||
origin.def.kind = type.def.kind;
|
||||
@ -1895,7 +1902,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
|
||||
// may not have a short_name yet. Note that we only process the lambda
|
||||
// parameter as a definition if it is in the same file as the reference,
|
||||
// as lambdas cannot be split across files.
|
||||
if (var.def.detailed_name.empty()) {
|
||||
if (!var.def.detailed_name[0]) {
|
||||
CXFile referenced_file;
|
||||
Range spell = referenced.get_spell(&referenced_file);
|
||||
if (file == referenced_file) {
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "language.h"
|
||||
#include "lsp.h"
|
||||
#include "maybe.h"
|
||||
#include "nt_string.h"
|
||||
#include "position.h"
|
||||
#include "serializer.h"
|
||||
#include "symbol.h"
|
||||
@ -69,21 +68,21 @@ template <typename D>
|
||||
struct NameMixin {
|
||||
std::string_view Name(bool qualified) const {
|
||||
auto self = static_cast<const D*>(this);
|
||||
return qualified ? std::string_view(
|
||||
self->detailed_name.c_str() + self->qual_name_offset,
|
||||
self->short_name_offset - self->qual_name_offset +
|
||||
return qualified
|
||||
? std::string_view(self->detailed_name + self->qual_name_offset,
|
||||
self->short_name_offset -
|
||||
self->qual_name_offset +
|
||||
self->short_name_size)
|
||||
: std::string_view(self->detailed_name.c_str() +
|
||||
self->short_name_offset,
|
||||
: std::string_view(self->detailed_name + self->short_name_offset,
|
||||
self->short_name_size);
|
||||
}
|
||||
};
|
||||
|
||||
struct FuncDef : NameMixin<FuncDef> {
|
||||
// General metadata.
|
||||
std::string detailed_name;
|
||||
NtString hover;
|
||||
NtString comments;
|
||||
const char* detailed_name = "";
|
||||
const char* hover = "";
|
||||
const char* comments = "";
|
||||
Maybe<Use> spell;
|
||||
Maybe<Use> extent;
|
||||
|
||||
@ -105,13 +104,6 @@ struct FuncDef : NameMixin<FuncDef> {
|
||||
clang::StorageClass storage = clang::SC_None;
|
||||
|
||||
std::vector<Usr> GetBases() const { return bases; }
|
||||
bool operator==(const FuncDef& o) const {
|
||||
return detailed_name == o.detailed_name && spell == o.spell &&
|
||||
extent == o.extent && declaring_type == o.declaring_type &&
|
||||
bases == o.bases && vars == o.vars && callees == o.callees &&
|
||||
kind == o.kind && storage == o.storage && hover == o.hover &&
|
||||
comments == o.comments;
|
||||
}
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(FuncDef,
|
||||
detailed_name,
|
||||
@ -139,10 +131,9 @@ struct IndexFunc : NameMixin<IndexFunc> {
|
||||
};
|
||||
|
||||
struct TypeDef : NameMixin<TypeDef> {
|
||||
// General metadata.
|
||||
std::string detailed_name;
|
||||
NtString hover;
|
||||
NtString comments;
|
||||
const char* detailed_name = "";
|
||||
const char* hover = "";
|
||||
const char* comments = "";
|
||||
|
||||
Maybe<Use> spell;
|
||||
Maybe<Use> extent;
|
||||
@ -164,12 +155,6 @@ struct TypeDef : NameMixin<TypeDef> {
|
||||
lsSymbolKind kind = lsSymbolKind::Unknown;
|
||||
|
||||
std::vector<Usr> GetBases() const { return bases; }
|
||||
bool operator==(const TypeDef& o) const {
|
||||
return detailed_name == o.detailed_name && spell == o.spell &&
|
||||
extent == o.extent && alias_of == o.alias_of && bases == o.bases &&
|
||||
types == o.types && funcs == o.funcs && vars == o.vars &&
|
||||
kind == o.kind && hover == o.hover && comments == o.comments;
|
||||
}
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(TypeDef,
|
||||
detailed_name,
|
||||
@ -199,9 +184,9 @@ struct IndexType {
|
||||
|
||||
struct VarDef : NameMixin<VarDef> {
|
||||
// General metadata.
|
||||
std::string detailed_name;
|
||||
NtString hover;
|
||||
NtString comments;
|
||||
const char* detailed_name = "";
|
||||
const char* hover = "";
|
||||
const char* comments = "";
|
||||
Maybe<Use> spell;
|
||||
Maybe<Use> extent;
|
||||
|
||||
@ -224,11 +209,6 @@ struct VarDef : NameMixin<VarDef> {
|
||||
}
|
||||
|
||||
std::vector<Usr> GetBases() const { return {}; }
|
||||
bool operator==(const VarDef& o) const {
|
||||
return detailed_name == o.detailed_name && spell == o.spell &&
|
||||
extent == o.extent && type == o.type && kind == o.kind &&
|
||||
storage == o.storage && hover == o.hover && comments == o.comments;
|
||||
}
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(VarDef,
|
||||
detailed_name,
|
||||
|
@ -94,9 +94,11 @@ void DoField(MessageHandler* m,
|
||||
}
|
||||
if (qualified)
|
||||
entry1.fieldName += def1->detailed_name;
|
||||
else
|
||||
entry1.fieldName += def1->detailed_name.substr(0, def1->qual_name_offset) +
|
||||
std::string(def1->Name(false));
|
||||
else {
|
||||
entry1.fieldName +=
|
||||
std::string_view(def1->detailed_name).substr(0, def1->qual_name_offset);
|
||||
entry1.fieldName += def1->Name(false);
|
||||
}
|
||||
if (def1->spell) {
|
||||
if (std::optional<lsLocation> loc =
|
||||
GetLsLocation(m->db, m->working_files, *def1->spell))
|
||||
|
@ -1,4 +1,3 @@
|
||||
#include "diagnostics_publisher.hh"
|
||||
#include "filesystem.hh"
|
||||
#include "include_complete.h"
|
||||
#include "log.hh"
|
||||
|
@ -11,7 +11,7 @@ std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) {
|
||||
std::optional<lsMarkedString> ret;
|
||||
WithEntity(db, sym, [&](const auto& entity) {
|
||||
if (const auto* def = entity.AnyDef())
|
||||
if (!def->comments.empty()) {
|
||||
if (def->comments[0]) {
|
||||
lsMarkedString m;
|
||||
m.value = def->comments;
|
||||
ret = m;
|
||||
@ -29,10 +29,10 @@ std::optional<lsMarkedString> GetHoverOrName(DB* db,
|
||||
if (const auto* def = entity.AnyDef()) {
|
||||
lsMarkedString m;
|
||||
m.language = LanguageIdentifier(lang);
|
||||
if (!def->hover.empty()) {
|
||||
if (def->hover[0]) {
|
||||
m.value = def->hover;
|
||||
ret = m;
|
||||
} else if (!def->detailed_name.empty()) {
|
||||
} else if (def->detailed_name[0]) {
|
||||
m.value = def->detailed_name;
|
||||
ret = m;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ void Reflect(Reader& visitor, lsRequestId& value) {
|
||||
value.value = visitor.GetInt();
|
||||
} else if (visitor.IsString()) {
|
||||
value.type = lsRequestId::kString;
|
||||
value.value = atoll(visitor.GetString().c_str());
|
||||
value.value = atoll(visitor.GetString());
|
||||
} else {
|
||||
value.type = lsRequestId::kNone;
|
||||
value.value = -1;
|
||||
|
@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
// Nullable null-terminated string, which is null if default constructed,
|
||||
// but non-null if assigned.
|
||||
// This is used in Query{Func,Type,Var}::def to reduce memory footprint.
|
||||
class NtString {
|
||||
using size_type = std::string::size_type;
|
||||
std::unique_ptr<char[]> str;
|
||||
|
||||
public:
|
||||
NtString() = default;
|
||||
NtString(NtString&& o) = default;
|
||||
NtString(const NtString& o) { *this = o; }
|
||||
NtString(std::string_view sv) { *this = sv; }
|
||||
|
||||
const char* c_str() const { return str.get(); }
|
||||
operator std::string_view() const {
|
||||
if (c_str())
|
||||
return c_str();
|
||||
return {};
|
||||
}
|
||||
bool empty() const { return !str || *c_str() == '\0'; }
|
||||
|
||||
void operator=(std::string_view sv) {
|
||||
str = std::unique_ptr<char[]>(new char[sv.size() + 1]);
|
||||
memcpy(str.get(), sv.data(), sv.size());
|
||||
str.get()[sv.size()] = '\0';
|
||||
}
|
||||
void operator=(const NtString& o) {
|
||||
*this = static_cast<std::string_view>(o);
|
||||
}
|
||||
bool operator==(const NtString& o) const {
|
||||
return str && o.str ? strcmp(c_str(), o.c_str()) == 0
|
||||
: c_str() == o.c_str();
|
||||
}
|
||||
};
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "clang_complete.h"
|
||||
#include "config.h"
|
||||
#include "diagnostics_publisher.hh"
|
||||
#include "include_complete.h"
|
||||
#include "log.hh"
|
||||
#include "lsp.h"
|
||||
@ -17,8 +16,42 @@
|
||||
#include <llvm/Support/Timer.h>
|
||||
using namespace llvm;
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
void DiagnosticsPublisher::Init() {
|
||||
frequencyMs_ = g_config->diagnostics.frequencyMs;
|
||||
match_ = std::make_unique<GroupMatch>(g_config->diagnostics.whitelist,
|
||||
g_config->diagnostics.blacklist);
|
||||
}
|
||||
|
||||
void DiagnosticsPublisher::Publish(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics) {
|
||||
// Cache diagnostics so we can show fixits.
|
||||
working_files->DoActionOnFile(path, [&](WorkingFile* working_file) {
|
||||
if (working_file)
|
||||
working_file->diagnostics_ = diagnostics;
|
||||
});
|
||||
|
||||
int64_t now =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch())
|
||||
.count();
|
||||
if (frequencyMs_ >= 0 && (nextPublish_ <= now || diagnostics.empty()) &&
|
||||
match_->IsMatch(path)) {
|
||||
nextPublish_ = now + frequencyMs_;
|
||||
|
||||
Out_TextDocumentPublishDiagnostics out;
|
||||
out.params.uri = lsDocumentUri::FromPath(path);
|
||||
out.params.diagnostics = diagnostics;
|
||||
ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, out);
|
||||
}
|
||||
}
|
||||
|
||||
namespace ccls::pipeline {
|
||||
namespace {
|
||||
|
||||
struct Index_Request {
|
||||
std::string path;
|
||||
std::vector<std::string> args;
|
||||
@ -31,9 +64,6 @@ struct Stdout_Request {
|
||||
std::string content;
|
||||
};
|
||||
|
||||
namespace ccls::pipeline {
|
||||
namespace {
|
||||
|
||||
MultiQueueWaiter* main_waiter;
|
||||
MultiQueueWaiter* indexer_waiter;
|
||||
MultiQueueWaiter* stdout_waiter;
|
||||
@ -115,8 +145,9 @@ std::unique_ptr<IndexFile> RawCacheLoad(
|
||||
if (!file_content || !serialized_indexed_content)
|
||||
return nullptr;
|
||||
|
||||
return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content,
|
||||
*file_content, IndexFile::kMajorVersion);
|
||||
return ccls::Deserialize(g_config->cacheFormat, path,
|
||||
*serialized_indexed_content, *file_content,
|
||||
IndexFile::kMajorVersion);
|
||||
}
|
||||
|
||||
bool Indexer_Parse(DiagnosticsPublisher* diag_pub,
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "lsp_diagnostic.h"
|
||||
#include "method.h"
|
||||
#include "query.h"
|
||||
|
||||
@ -7,12 +8,24 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class DiagnosticsPublisher;
|
||||
struct GroupMatch;
|
||||
struct VFS;
|
||||
struct Project;
|
||||
struct WorkingFiles;
|
||||
struct lsBaseOutMessage;
|
||||
|
||||
class DiagnosticsPublisher {
|
||||
std::unique_ptr<GroupMatch> match_;
|
||||
int64_t nextPublish_ = 0;
|
||||
int frequencyMs_;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
void Publish(WorkingFiles* working_files,
|
||||
std::string path,
|
||||
std::vector<lsDiagnostic> diagnostics);
|
||||
};
|
||||
|
||||
namespace ccls::pipeline {
|
||||
|
||||
void Init();
|
||||
|
12
src/query.cc
12
src/query.cc
@ -189,7 +189,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
}
|
||||
for (auto& it : current->usr2func) {
|
||||
auto& func = it.second;
|
||||
if (func.def.spell && func.def.detailed_name.size())
|
||||
if (func.def.spell && func.def.detailed_name[0])
|
||||
r.funcs_def_update.emplace_back(it.first, func.def);
|
||||
r.funcs_declarations[func.usr].second = std::move(func.declarations);
|
||||
r.funcs_uses[func.usr].second = std::move(func.uses);
|
||||
@ -208,7 +208,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
};
|
||||
for (auto& it : current->usr2type) {
|
||||
auto& type = it.second;
|
||||
if (type.def.spell && type.def.detailed_name.size())
|
||||
if (type.def.spell && type.def.detailed_name[0])
|
||||
r.types_def_update.emplace_back(it.first, type.def);
|
||||
r.types_declarations[type.usr].second = std::move(type.declarations);
|
||||
r.types_uses[type.usr].second = std::move(type.uses);
|
||||
@ -226,7 +226,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||
}
|
||||
for (auto& it : current->usr2var) {
|
||||
auto& var = it.second;
|
||||
if (var.def.spell && var.def.detailed_name.size())
|
||||
if (var.def.spell && var.def.detailed_name[0])
|
||||
r.vars_def_update.emplace_back(it.first, var.def);
|
||||
r.vars_declarations[var.usr].second = std::move(var.declarations);
|
||||
r.vars_uses[var.usr].second = std::move(var.uses);
|
||||
@ -353,7 +353,7 @@ int DB::Update(QueryFile::DefUpdate&& u) {
|
||||
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
|
||||
for (auto& u : us) {
|
||||
auto& def = u.second;
|
||||
assert(!def.detailed_name.empty());
|
||||
assert(def.detailed_name[0]);
|
||||
AssignFileId(file_id, def.spell);
|
||||
AssignFileId(file_id, def.extent);
|
||||
AssignFileId(file_id, def.callees);
|
||||
@ -370,7 +370,7 @@ void DB::Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
|
||||
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us) {
|
||||
for (auto& u : us) {
|
||||
auto& def = u.second;
|
||||
assert(!def.detailed_name.empty());
|
||||
assert(def.detailed_name[0]);
|
||||
AssignFileId(file_id, def.spell);
|
||||
AssignFileId(file_id, def.extent);
|
||||
auto R = type_usr.try_emplace({u.first}, type_usr.size());
|
||||
@ -387,7 +387,7 @@ void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us) {
|
||||
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us) {
|
||||
for (auto& u : us) {
|
||||
auto& def = u.second;
|
||||
assert(!def.detailed_name.empty());
|
||||
assert(def.detailed_name[0]);
|
||||
AssignFileId(file_id, def.spell);
|
||||
AssignFileId(file_id, def.extent);
|
||||
auto R = var_usr.try_emplace({u.first}, var_usr.size());
|
||||
|
@ -1,12 +1,15 @@
|
||||
#include "serializer.h"
|
||||
|
||||
#include "filesystem.hh"
|
||||
#include "indexer.h"
|
||||
#include "log.hh"
|
||||
#include "serializers/binary.h"
|
||||
#include "serializers/json.h"
|
||||
|
||||
#include "indexer.h"
|
||||
#include <llvm/ADT/CachedHashString.h>
|
||||
#include <llvm/ADT/DenseSet.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace llvm;
|
||||
@ -131,14 +134,12 @@ void Reflect(Writer& visitor, std::string_view& data) {
|
||||
visitor.String(&data[0], (rapidjson::SizeType)data.size());
|
||||
}
|
||||
|
||||
void Reflect(Reader& visitor, NtString& value) {
|
||||
if (!visitor.IsString())
|
||||
throw std::invalid_argument("std::string");
|
||||
value = visitor.GetString();
|
||||
void Reflect(Reader& vis, const char*& v) {
|
||||
const char* str = vis.GetString();
|
||||
v = ccls::Intern(str);
|
||||
}
|
||||
void Reflect(Writer& visitor, NtString& value) {
|
||||
const char* s = value.c_str();
|
||||
visitor.String(s ? s : "");
|
||||
void Reflect(Writer& vis, const char*& v) {
|
||||
vis.String(v);
|
||||
}
|
||||
|
||||
void Reflect(Reader& visitor, JsonNull& value) {
|
||||
@ -223,9 +224,9 @@ void ReflectHoverAndComments(Reader& visitor, Def& def) {
|
||||
template <typename Def>
|
||||
void ReflectHoverAndComments(Writer& visitor, Def& def) {
|
||||
// Don't emit empty hover and comments in JSON test mode.
|
||||
if (!gTestOutputMode || !def.hover.empty())
|
||||
if (!gTestOutputMode || def.hover[0])
|
||||
ReflectMember(visitor, "hover", def.hover);
|
||||
if (!gTestOutputMode || !def.comments.empty())
|
||||
if (!gTestOutputMode || def.comments[0])
|
||||
ReflectMember(visitor, "comments", def.comments);
|
||||
}
|
||||
|
||||
@ -234,7 +235,7 @@ void ReflectShortName(Reader& visitor, Def& def) {
|
||||
if (gTestOutputMode) {
|
||||
std::string short_name;
|
||||
ReflectMember(visitor, "short_name", short_name);
|
||||
def.short_name_offset = def.detailed_name.find(short_name);
|
||||
def.short_name_offset = std::string_view(def.detailed_name).find(short_name);
|
||||
assert(def.short_name_offset != std::string::npos);
|
||||
def.short_name_size = short_name.size();
|
||||
} else {
|
||||
@ -246,8 +247,8 @@ void ReflectShortName(Reader& visitor, Def& def) {
|
||||
template <typename Def>
|
||||
void ReflectShortName(Writer& visitor, Def& def) {
|
||||
if (gTestOutputMode) {
|
||||
std::string short_name(
|
||||
def.detailed_name.substr(def.short_name_offset, def.short_name_size));
|
||||
std::string_view short_name(def.detailed_name + def.short_name_offset,
|
||||
def.short_name_size);
|
||||
ReflectMember(visitor, "short_name", short_name);
|
||||
} else {
|
||||
ReflectMember(visitor, "short_name_offset", def.short_name_offset);
|
||||
@ -357,6 +358,21 @@ void Reflect(Writer& visitor, SerializeFormat& value) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace ccls {
|
||||
static BumpPtrAllocator Alloc;
|
||||
static DenseSet<StringRef> Strings;
|
||||
static std::mutex AllocMutex;
|
||||
|
||||
const char* Intern(const std::string& str) {
|
||||
if (str.empty()) return "";
|
||||
StringRef Str(str.data(), str.size() + 1);
|
||||
std::lock_guard lock(AllocMutex);
|
||||
auto R = Strings.insert(Str);
|
||||
if (R.second)
|
||||
*R.first = Str.copy(Alloc);
|
||||
return R.first->data();
|
||||
}
|
||||
|
||||
std::string Serialize(SerializeFormat format, IndexFile& file) {
|
||||
switch (format) {
|
||||
case SerializeFormat::Binary: {
|
||||
@ -451,3 +467,4 @@ std::unique_ptr<IndexFile> Deserialize(
|
||||
file->path = path;
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "maybe.h"
|
||||
#include "nt_string.h"
|
||||
|
||||
#include <llvm/Support/Compiler.h>
|
||||
|
||||
@ -42,7 +41,7 @@ class Reader {
|
||||
virtual int64_t GetInt64() = 0;
|
||||
virtual uint64_t GetUInt64() = 0;
|
||||
virtual double GetDouble() = 0;
|
||||
virtual std::string GetString() = 0;
|
||||
virtual const char* GetString() = 0;
|
||||
|
||||
virtual bool HasMember(const char* x) = 0;
|
||||
virtual std::unique_ptr<Reader> operator[](const char* x) = 0;
|
||||
@ -180,8 +179,8 @@ void Reflect(Writer& visitor, std::string& value);
|
||||
void Reflect(Reader& visitor, std::string_view& view);
|
||||
void Reflect(Writer& visitor, std::string_view& view);
|
||||
|
||||
void Reflect(Reader& visitor, NtString& value);
|
||||
void Reflect(Writer& visitor, NtString& value);
|
||||
void Reflect(Reader& vis, const char*& v);
|
||||
void Reflect(Writer& vis, const char*& v);
|
||||
|
||||
void Reflect(Reader& visitor, JsonNull& value);
|
||||
void Reflect(Writer& visitor, JsonNull& value);
|
||||
@ -322,6 +321,8 @@ void ReflectMember(Writer& vis, const char* name, T& v) {
|
||||
|
||||
// API
|
||||
|
||||
namespace ccls {
|
||||
const char* Intern(const std::string& str);
|
||||
std::string Serialize(SerializeFormat format, IndexFile& file);
|
||||
std::unique_ptr<IndexFile> Deserialize(
|
||||
SerializeFormat format,
|
||||
@ -329,3 +330,4 @@ std::unique_ptr<IndexFile> Deserialize(
|
||||
const std::string& serialized_index_content,
|
||||
const std::string& file_content,
|
||||
std::optional<int> expected_version);
|
||||
}
|
||||
|
@ -52,14 +52,13 @@ class BinaryReader : public Reader {
|
||||
uint32_t GetUInt32() override { return VarUInt(); }
|
||||
uint64_t GetUInt64() override { return VarUInt(); }
|
||||
double GetDouble() override { return Get<double>(); }
|
||||
std::string GetString() override {
|
||||
if (auto n = VarUInt()) {
|
||||
std::string ret(p_, n);
|
||||
p_ += n;
|
||||
const char* GetString() override {
|
||||
const char* ret = p_;
|
||||
while (*p_)
|
||||
p_++;
|
||||
p_++;
|
||||
return ret;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool HasMember(const char* x) override { return true; }
|
||||
std::unique_ptr<Reader> operator[](const char* x) override { return {}; }
|
||||
@ -118,9 +117,8 @@ class BinaryWriter : public Writer {
|
||||
void Double(double x) override { Pack(x); }
|
||||
void String(const char* x) override { String(x, strlen(x)); }
|
||||
void String(const char* x, size_t len) override {
|
||||
VarUInt(len);
|
||||
auto i = buf_.size();
|
||||
buf_.resize(i + len);
|
||||
buf_.resize(i + len + 1);
|
||||
memcpy(buf_.data() + i, x, len);
|
||||
}
|
||||
void StartArray(size_t n) override { VarUInt(n); }
|
||||
|
@ -29,7 +29,7 @@ class JsonReader : public Reader {
|
||||
uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); }
|
||||
uint64_t GetUInt64() override { return m_->GetUint64(); }
|
||||
double GetDouble() override { return m_->GetDouble(); }
|
||||
std::string GetString() override { return m_->GetString(); }
|
||||
const char* GetString() override { return m_->GetString(); }
|
||||
|
||||
bool HasMember(const char* x) override { return m_->HasMember(x); }
|
||||
std::unique_ptr<Reader> operator[](const char* x) override {
|
||||
|
@ -191,9 +191,9 @@ void DiffDocuments(std::string path,
|
||||
|
||||
void VerifySerializeToFrom(IndexFile* file) {
|
||||
std::string expected = file->ToString();
|
||||
std::string serialized = Serialize(SerializeFormat::Json, *file);
|
||||
std::string serialized = ccls::Serialize(SerializeFormat::Json, *file);
|
||||
std::unique_ptr<IndexFile> result =
|
||||
Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
|
||||
ccls::Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
|
||||
std::nullopt /*expected_version*/);
|
||||
std::string actual = result->ToString();
|
||||
if (expected != actual) {
|
||||
|
Loading…
Reference in New Issue
Block a user