Internalize strings & remove diagnostics_publisher.cc

This commit is contained in:
Fangrui Song 2018-06-07 21:53:41 -07:00
parent d21476d7ee
commit 1830103ec6
20 changed files with 170 additions and 217 deletions

View File

@ -193,7 +193,6 @@ target_sources(ccls PRIVATE
src/clang_tu.cc src/clang_tu.cc
src/clang_utils.cc src/clang_utils.cc
src/config.cc src/config.cc
src/diagnostics_publisher.cc
src/file_consumer.cc src/file_consumer.cc
src/filesystem.cc src/filesystem.cc
src/fuzzy_match.cc src/fuzzy_match.cc

View File

@ -259,7 +259,7 @@ std::string ClangCursor::get_type_description() const {
return ::ToString(clang_getTypeSpelling(type)); return ::ToString(clang_getTypeSpelling(type));
} }
NtString ClangCursor::get_comments() const { std::string ClangCursor::get_comments() const {
CXSourceRange range = clang_Cursor_getCommentRange(cx_cursor); CXSourceRange range = clang_Cursor_getCommentRange(cx_cursor);
if (clang_Range_isNull(range)) if (clang_Range_isNull(range))
return {}; return {};
@ -317,7 +317,7 @@ NtString ClangCursor::get_comments() const {
ret.pop_back(); ret.pop_back();
if (ret.empty()) if (ret.empty())
return {}; return {};
return static_cast<std::string_view>(ret); return ret;
} }
std::string ClangCursor::ToString() const { std::string ClangCursor::ToString() const {

View File

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "nt_string.h"
#include "position.h" #include "position.h"
#include <clang-c/Index.h> #include <clang-c/Index.h>
@ -86,7 +85,7 @@ class ClangCursor {
bool is_valid_kind() const; bool is_valid_kind() const;
std::string get_type_description() const; std::string get_type_description() const;
NtString get_comments() const; std::string get_comments() const;
std::string ToString() const; std::string ToString() const;

View File

@ -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);
}
}

View File

@ -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);
};

View File

@ -3,6 +3,7 @@
#include "log.hh" #include "log.hh"
#include "platform.h" #include "platform.h"
#include "serializer.h" #include "serializer.h"
using ccls::Intern;
#include <clang/AST/AST.h> #include <clang/AST/AST.h>
#include <clang/Frontend/ASTUnit.h> #include <clang/Frontend/ASTUnit.h>
@ -523,8 +524,10 @@ void SetTypeName(IndexType& type,
// ns {}` which are not qualified. // ns {}` which are not qualified.
// type->def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor); // type->def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor);
int short_name_offset, short_name_size; 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); param->ns.QualifiedName(container ? container : &parent, name);
type.def.detailed_name = Intern(detailed);
type.def.qual_name_offset = 0; type.def.qual_name_offset = 0;
type.def.short_name_offset = short_name_offset; type.def.short_name_offset = short_name_offset;
type.def.short_name_size = short_name_size; type.def.short_name_size = short_name_size;
@ -558,7 +561,7 @@ IndexType* ResolveToDeclarationType(IndexFile* db,
if (!usr) if (!usr)
return nullptr; return nullptr;
IndexType& typ = db->ToType(*usr); IndexType& typ = db->ToType(*usr);
if (typ.def.detailed_name.empty()) { if (!typ.def.detailed_name[0]) {
std::string name = declaration.get_spell_name(); std::string name = declaration.get_spell_name();
SetTypeName(typ, declaration, nullptr, name.c_str(), param); 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) if (type_name.find("(lambda at") != std::string::npos)
type_name = "lambda"; type_name = "lambda";
if (g_config->index.comments) 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)); def.storage = GetStorageC(clang_Cursor_getStorageClass(cursor.cx_cursor));
// TODO how to make PrettyPrint'ed variable name qualified? // TODO how to make PrettyPrint'ed variable name qualified?
@ -607,16 +610,16 @@ void SetVarDetail(IndexVar& var,
else else
hover += std::to_string(TD->getInitVal().getSExtValue()); 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.qual_name_offset = 0;
def.hover = hover; def.hover = Intern(hover);
} else { } else {
#if 0 #if 0
def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor, false); def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor, false);
#else #else
int offset = type_name.size(); int offset = type_name.size();
offset += ConcatTypeAndName(type_name, qualified_name); offset += ConcatTypeAndName(type_name, qualified_name);
def.detailed_name = type_name; def.detailed_name = Intern(type_name);
def.qual_name_offset = offset; def.qual_name_offset = offset;
def.short_name_offset += offset; def.short_name_offset += offset;
// Append the textual initializer, bit field, constructor to |hover|. // 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), std::optional<int> spell_end = fc.ToOffset(spell_p),
extent_end = fc.ToOffset(extent_p); extent_end = fc.ToOffset(extent_p);
if (extent_end && *spell_end < *extent_end) if (extent_end && *spell_end < *extent_end)
def.hover = std::string(def.detailed_name.c_str()) + def.hover =
fc.content.substr(*spell_end, *extent_end - *spell_end); Intern(std::string(def.detailed_name) +
fc.content.substr(*spell_end, *extent_end - *spell_end));
} }
} }
skip:; skip:;
@ -714,7 +718,7 @@ void OnIndexReference_Function(IndexFile* db,
// static // static
const int IndexFile::kMajorVersion = 16; 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) IndexFile::IndexFile(const std::string& path, const std::string& contents)
: path(path), file_contents(contents) {} : path(path), file_contents(contents) {}
@ -741,7 +745,7 @@ IndexVar& IndexFile::ToVar(Usr usr) {
} }
std::string IndexFile::ToString() { std::string IndexFile::ToString() {
return Serialize(SerializeFormat::Json, *this); return ccls::Serialize(SerializeFormat::Json, *this);
} }
void Uniquify(std::vector<Usr>& usrs) { void Uniquify(std::vector<Usr>& usrs) {
@ -1197,16 +1201,17 @@ ClangCursor::VisitResult VisitMacroDefinitionAndExpansions(ClangCursor cursor,
IndexVar& var_def = db->ToVar(decl_usr); IndexVar& var_def = db->ToVar(decl_usr);
if (cursor.get_kind() == CXCursor_MacroDefinition) { if (cursor.get_kind() == CXCursor_MacroDefinition) {
CXSourceRange cx_extent = clang_getCursorExtent(cursor.cx_cursor); 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.qual_name_offset = 0;
var_def.def.short_name_offset = 0; var_def.def.short_name_offset = 0;
var_def.def.short_name_size = 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 = 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; var_def.def.kind = lsSymbolKind::Macro;
if (g_config->index.comments) if (g_config->index.comments)
var_def.def.comments = cursor.get_comments(); var_def.def.comments = Intern(cursor.get_comments());
var_def.def.spell = var_def.def.spell =
SetUse(db, decl_loc_spelling, parent, Role::Definition); SetUse(db, decl_loc_spelling, parent, Role::Definition);
var_def.def.extent = SetUse( var_def.def.extent = SetUse(
@ -1244,7 +1249,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor); ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor);
if (ref_cursor.get_kind() == CXCursor_NonTypeTemplateParameter) { if (ref_cursor.get_kind() == CXCursor_NonTypeTemplateParameter) {
IndexVar& ref_var = db->ToVar(ref_cursor); 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 sem_parent = ref_cursor.get_semantic_parent();
ClangCursor lex_parent = ref_cursor.get_lexical_parent(); ClangCursor lex_parent = ref_cursor.get_lexical_parent();
ref_var.def.spell = ref_var.def.spell =
@ -1298,7 +1303,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
// CXCursor_TemplateTemplateParameter can be visited by visiting // CXCursor_TemplateTemplateParameter can be visited by visiting
// CXCursor_TranslationUnit, but not (confirm this) by visiting // CXCursor_TranslationUnit, but not (confirm this) by visiting
// {Class,Function}Template. Thus we need to initialize it here. // {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 sem_parent = ref_cursor.get_semantic_parent();
ClangCursor lex_parent = ref_cursor.get_lexical_parent(); ClangCursor lex_parent = ref_cursor.get_lexical_parent();
ref_type.def.spell = ref_type.def.spell =
@ -1308,11 +1313,11 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
#if 0 && CINDEX_HAVE_PRETTY #if 0 && CINDEX_HAVE_PRETTY
ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor); ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor);
#else #else
ref_type.def.detailed_name = ref_cursor.get_spell_name(); ref_type.def.detailed_name = Intern(ref_cursor.get_spell_name());
#endif #endif
ref_type.def.short_name_offset = 0; ref_type.def.short_name_offset = 0;
ref_type.def.short_name_size = 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; ref_type.def.kind = lsSymbolKind::TypeParameter;
} }
AddUseSpell(db, ref_type.uses, cursor); AddUseSpell(db, ref_type.uses, cursor);
@ -1328,7 +1333,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
// CXCursor_TemplateTypeParameter can be visited by visiting // CXCursor_TemplateTypeParameter can be visited by visiting
// CXCursor_TranslationUnit, but not (confirm this) by visiting // CXCursor_TranslationUnit, but not (confirm this) by visiting
// {Class,Function}Template. Thus we need to initialize it here. // {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 sem_parent = ref_cursor.get_semantic_parent();
ClangCursor lex_parent = ref_cursor.get_lexical_parent(); ClangCursor lex_parent = ref_cursor.get_lexical_parent();
ref_type.def.spell = 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 // template<class T> void f(T t){} // weird, the name is empty
ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor); ref_type->def.detailed_name = param->PrettyPrintCursor(ref_cursor.cx_cursor);
#else #else
ref_type.def.detailed_name = ref_cursor.get_spell_name(); ref_type.def.detailed_name = Intern(ref_cursor.get_spell_name());
#endif #endif
ref_type.def.short_name_offset = 0; ref_type.def.short_name_offset = 0;
ref_type.def.short_name_size = 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; ref_type.def.kind = lsSymbolKind::TypeParameter;
} }
AddUseSpell(db, ref_type.uses, cursor); AddUseSpell(db, ref_type.uses, cursor);
@ -1443,7 +1448,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
Range spell = cursor.get_spell(); Range spell = cursor.get_spell();
IndexType& ns = db->ToType(HashUsr(decl->entityInfo->USR)); IndexType& ns = db->ToType(HashUsr(decl->entityInfo->USR));
ns.def.kind = GetSymbolKind(decl->entityInfo->kind); 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, SetTypeName(ns, cursor, decl->semanticContainer, decl->entityInfo->name,
param); param);
ns.def.spell = SetUse(db, spell, sem_parent, Role::Definition); 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); IndexFunc& func = db->ToFunc(decl_cursor_resolved);
if (g_config->index.comments) 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.kind = GetSymbolKind(decl->entityInfo->kind);
func.def.storage = func.def.storage =
GetStorageC(clang_Cursor_getStorageClass(decl->cursor)); 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 // indexing the definition, then there will not be any (ie) outline
// information. // information.
if (!is_template_specialization) { 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) = func.def.short_name_offset, func.def.short_name_size) =
param->PrettyPrintCursor(decl->cursor, decl->entityInfo->name); param->PrettyPrintCursor(decl->cursor, decl->entityInfo->name);
func.def.detailed_name = Intern(detailed);
// CXCursor_OverloadedDeclRef in templates are not processed by // CXCursor_OverloadedDeclRef in templates are not processed by
// OnIndexReference, thus we use TemplateVisitor to collect function // OnIndexReference, thus we use TemplateVisitor to collect function
@ -1668,7 +1675,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
decl->entityInfo->name, param); decl->entityInfo->name, param);
type.def.kind = GetSymbolKind(decl->entityInfo->kind); type.def.kind = GetSymbolKind(decl->entityInfo->kind);
if (g_config->index.comments) 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 // For Typedef/CXXTypeAlias spanning a few lines, display the declaration
// line, with spelling name replaced with qualified name. // 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), spell_end = fc.ToOffset(spell.end),
extent_end = fc.ToOffset(extent.end); extent_end = fc.ToOffset(extent.end);
if (extent_start && spell_start && spell_end && 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) + fc.content.substr(*extent_start, *spell_start - *extent_start) +
type.def.detailed_name.c_str() + type.def.detailed_name +
fc.content.substr(*spell_end, *extent_end - *spell_end); fc.content.substr(*spell_end, *extent_end - *spell_end));
} }
} }
@ -1711,7 +1718,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
param); param);
type.def.kind = GetSymbolKind(decl->entityInfo->kind); type.def.kind = GetSymbolKind(decl->entityInfo->kind);
if (g_config->index.comments) if (g_config->index.comments)
type.def.comments = cursor.get_comments(); type.def.comments = Intern(cursor.get_comments());
// } // }
if (decl->isDefinition) { if (decl->isDefinition) {
@ -1743,7 +1750,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
// template<class T> class function; // not visited by // template<class T> class function; // not visited by
// OnIndexDeclaration template<> class function<int> {}; // current // OnIndexDeclaration template<> class function<int> {}; // current
// cursor // cursor
if (origin.def.detailed_name.empty()) { if (!origin.def.detailed_name[0]) {
SetTypeName(origin, origin_cursor, nullptr, SetTypeName(origin, origin_cursor, nullptr,
&type.def.Name(false)[0], param); &type.def.Name(false)[0], param);
origin.def.kind = type.def.kind; 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 // 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, // parameter as a definition if it is in the same file as the reference,
// as lambdas cannot be split across files. // as lambdas cannot be split across files.
if (var.def.detailed_name.empty()) { if (!var.def.detailed_name[0]) {
CXFile referenced_file; CXFile referenced_file;
Range spell = referenced.get_spell(&referenced_file); Range spell = referenced.get_spell(&referenced_file);
if (file == referenced_file) { if (file == referenced_file) {

View File

@ -6,7 +6,6 @@
#include "language.h" #include "language.h"
#include "lsp.h" #include "lsp.h"
#include "maybe.h" #include "maybe.h"
#include "nt_string.h"
#include "position.h" #include "position.h"
#include "serializer.h" #include "serializer.h"
#include "symbol.h" #include "symbol.h"
@ -69,21 +68,21 @@ template <typename D>
struct NameMixin { struct NameMixin {
std::string_view Name(bool qualified) const { std::string_view Name(bool qualified) const {
auto self = static_cast<const D*>(this); auto self = static_cast<const D*>(this);
return qualified ? std::string_view( return qualified
self->detailed_name.c_str() + self->qual_name_offset, ? std::string_view(self->detailed_name + self->qual_name_offset,
self->short_name_offset - self->qual_name_offset + self->short_name_offset -
self->short_name_size) self->qual_name_offset +
: std::string_view(self->detailed_name.c_str() + self->short_name_size)
self->short_name_offset, : std::string_view(self->detailed_name + self->short_name_offset,
self->short_name_size); self->short_name_size);
} }
}; };
struct FuncDef : NameMixin<FuncDef> { struct FuncDef : NameMixin<FuncDef> {
// General metadata. // General metadata.
std::string detailed_name; const char* detailed_name = "";
NtString hover; const char* hover = "";
NtString comments; const char* comments = "";
Maybe<Use> spell; Maybe<Use> spell;
Maybe<Use> extent; Maybe<Use> extent;
@ -105,13 +104,6 @@ struct FuncDef : NameMixin<FuncDef> {
clang::StorageClass storage = clang::SC_None; clang::StorageClass storage = clang::SC_None;
std::vector<Usr> GetBases() const { return bases; } 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, MAKE_REFLECT_STRUCT(FuncDef,
detailed_name, detailed_name,
@ -139,10 +131,9 @@ struct IndexFunc : NameMixin<IndexFunc> {
}; };
struct TypeDef : NameMixin<TypeDef> { struct TypeDef : NameMixin<TypeDef> {
// General metadata. const char* detailed_name = "";
std::string detailed_name; const char* hover = "";
NtString hover; const char* comments = "";
NtString comments;
Maybe<Use> spell; Maybe<Use> spell;
Maybe<Use> extent; Maybe<Use> extent;
@ -164,12 +155,6 @@ struct TypeDef : NameMixin<TypeDef> {
lsSymbolKind kind = lsSymbolKind::Unknown; lsSymbolKind kind = lsSymbolKind::Unknown;
std::vector<Usr> GetBases() const { return bases; } 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, MAKE_REFLECT_STRUCT(TypeDef,
detailed_name, detailed_name,
@ -199,9 +184,9 @@ struct IndexType {
struct VarDef : NameMixin<VarDef> { struct VarDef : NameMixin<VarDef> {
// General metadata. // General metadata.
std::string detailed_name; const char* detailed_name = "";
NtString hover; const char* hover = "";
NtString comments; const char* comments = "";
Maybe<Use> spell; Maybe<Use> spell;
Maybe<Use> extent; Maybe<Use> extent;
@ -224,11 +209,6 @@ struct VarDef : NameMixin<VarDef> {
} }
std::vector<Usr> GetBases() const { return {}; } 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, MAKE_REFLECT_STRUCT(VarDef,
detailed_name, detailed_name,

View File

@ -94,9 +94,11 @@ void DoField(MessageHandler* m,
} }
if (qualified) if (qualified)
entry1.fieldName += def1->detailed_name; entry1.fieldName += def1->detailed_name;
else else {
entry1.fieldName += def1->detailed_name.substr(0, def1->qual_name_offset) + entry1.fieldName +=
std::string(def1->Name(false)); std::string_view(def1->detailed_name).substr(0, def1->qual_name_offset);
entry1.fieldName += def1->Name(false);
}
if (def1->spell) { if (def1->spell) {
if (std::optional<lsLocation> loc = if (std::optional<lsLocation> loc =
GetLsLocation(m->db, m->working_files, *def1->spell)) GetLsLocation(m->db, m->working_files, *def1->spell))

View File

@ -1,4 +1,3 @@
#include "diagnostics_publisher.hh"
#include "filesystem.hh" #include "filesystem.hh"
#include "include_complete.h" #include "include_complete.h"
#include "log.hh" #include "log.hh"

View File

@ -11,7 +11,7 @@ std::optional<lsMarkedString> GetComments(DB* db, SymbolRef sym) {
std::optional<lsMarkedString> ret; std::optional<lsMarkedString> ret;
WithEntity(db, sym, [&](const auto& entity) { WithEntity(db, sym, [&](const auto& entity) {
if (const auto* def = entity.AnyDef()) if (const auto* def = entity.AnyDef())
if (!def->comments.empty()) { if (def->comments[0]) {
lsMarkedString m; lsMarkedString m;
m.value = def->comments; m.value = def->comments;
ret = m; ret = m;
@ -29,10 +29,10 @@ std::optional<lsMarkedString> GetHoverOrName(DB* db,
if (const auto* def = entity.AnyDef()) { if (const auto* def = entity.AnyDef()) {
lsMarkedString m; lsMarkedString m;
m.language = LanguageIdentifier(lang); m.language = LanguageIdentifier(lang);
if (!def->hover.empty()) { if (def->hover[0]) {
m.value = def->hover; m.value = def->hover;
ret = m; ret = m;
} else if (!def->detailed_name.empty()) { } else if (def->detailed_name[0]) {
m.value = def->detailed_name; m.value = def->detailed_name;
ret = m; ret = m;
} }

View File

@ -18,7 +18,7 @@ void Reflect(Reader& visitor, lsRequestId& value) {
value.value = visitor.GetInt(); value.value = visitor.GetInt();
} else if (visitor.IsString()) { } else if (visitor.IsString()) {
value.type = lsRequestId::kString; value.type = lsRequestId::kString;
value.value = atoll(visitor.GetString().c_str()); value.value = atoll(visitor.GetString());
} else { } else {
value.type = lsRequestId::kNone; value.type = lsRequestId::kNone;
value.value = -1; value.value = -1;

View File

@ -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();
}
};

View File

@ -2,7 +2,6 @@
#include "clang_complete.h" #include "clang_complete.h"
#include "config.h" #include "config.h"
#include "diagnostics_publisher.hh"
#include "include_complete.h" #include "include_complete.h"
#include "log.hh" #include "log.hh"
#include "lsp.h" #include "lsp.h"
@ -17,8 +16,42 @@
#include <llvm/Support/Timer.h> #include <llvm/Support/Timer.h>
using namespace llvm; using namespace llvm;
#include <chrono>
#include <thread> #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 { struct Index_Request {
std::string path; std::string path;
std::vector<std::string> args; std::vector<std::string> args;
@ -31,9 +64,6 @@ struct Stdout_Request {
std::string content; std::string content;
}; };
namespace ccls::pipeline {
namespace {
MultiQueueWaiter* main_waiter; MultiQueueWaiter* main_waiter;
MultiQueueWaiter* indexer_waiter; MultiQueueWaiter* indexer_waiter;
MultiQueueWaiter* stdout_waiter; MultiQueueWaiter* stdout_waiter;
@ -115,8 +145,9 @@ std::unique_ptr<IndexFile> RawCacheLoad(
if (!file_content || !serialized_indexed_content) if (!file_content || !serialized_indexed_content)
return nullptr; return nullptr;
return Deserialize(g_config->cacheFormat, path, *serialized_indexed_content, return ccls::Deserialize(g_config->cacheFormat, path,
*file_content, IndexFile::kMajorVersion); *serialized_indexed_content, *file_content,
IndexFile::kMajorVersion);
} }
bool Indexer_Parse(DiagnosticsPublisher* diag_pub, bool Indexer_Parse(DiagnosticsPublisher* diag_pub,

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "lsp_diagnostic.h"
#include "method.h" #include "method.h"
#include "query.h" #include "query.h"
@ -7,12 +8,24 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
class DiagnosticsPublisher; struct GroupMatch;
struct VFS; struct VFS;
struct Project; struct Project;
struct WorkingFiles; struct WorkingFiles;
struct lsBaseOutMessage; 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 { namespace ccls::pipeline {
void Init(); void Init();

View File

@ -189,7 +189,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
} }
for (auto& it : current->usr2func) { for (auto& it : current->usr2func) {
auto& func = it.second; 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_def_update.emplace_back(it.first, func.def);
r.funcs_declarations[func.usr].second = std::move(func.declarations); r.funcs_declarations[func.usr].second = std::move(func.declarations);
r.funcs_uses[func.usr].second = std::move(func.uses); r.funcs_uses[func.usr].second = std::move(func.uses);
@ -208,7 +208,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
}; };
for (auto& it : current->usr2type) { for (auto& it : current->usr2type) {
auto& type = it.second; 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_def_update.emplace_back(it.first, type.def);
r.types_declarations[type.usr].second = std::move(type.declarations); r.types_declarations[type.usr].second = std::move(type.declarations);
r.types_uses[type.usr].second = std::move(type.uses); r.types_uses[type.usr].second = std::move(type.uses);
@ -226,7 +226,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
} }
for (auto& it : current->usr2var) { for (auto& it : current->usr2var) {
auto& var = it.second; 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_def_update.emplace_back(it.first, var.def);
r.vars_declarations[var.usr].second = std::move(var.declarations); r.vars_declarations[var.usr].second = std::move(var.declarations);
r.vars_uses[var.usr].second = std::move(var.uses); 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) { void DB::Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
for (auto& u : us) { for (auto& u : us) {
auto& def = u.second; auto& def = u.second;
assert(!def.detailed_name.empty()); assert(def.detailed_name[0]);
AssignFileId(file_id, def.spell); AssignFileId(file_id, def.spell);
AssignFileId(file_id, def.extent); AssignFileId(file_id, def.extent);
AssignFileId(file_id, def.callees); 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) { void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us) {
for (auto& u : us) { for (auto& u : us) {
auto& def = u.second; auto& def = u.second;
assert(!def.detailed_name.empty()); assert(def.detailed_name[0]);
AssignFileId(file_id, def.spell); AssignFileId(file_id, def.spell);
AssignFileId(file_id, def.extent); AssignFileId(file_id, def.extent);
auto R = type_usr.try_emplace({u.first}, type_usr.size()); 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) { void DB::Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us) {
for (auto& u : us) { for (auto& u : us) {
auto& def = u.second; auto& def = u.second;
assert(!def.detailed_name.empty()); assert(def.detailed_name[0]);
AssignFileId(file_id, def.spell); AssignFileId(file_id, def.spell);
AssignFileId(file_id, def.extent); AssignFileId(file_id, def.extent);
auto R = var_usr.try_emplace({u.first}, var_usr.size()); auto R = var_usr.try_emplace({u.first}, var_usr.size());

View File

@ -1,12 +1,15 @@
#include "serializer.h" #include "serializer.h"
#include "filesystem.hh" #include "filesystem.hh"
#include "indexer.h"
#include "log.hh" #include "log.hh"
#include "serializers/binary.h" #include "serializers/binary.h"
#include "serializers/json.h" #include "serializers/json.h"
#include "indexer.h" #include <llvm/ADT/CachedHashString.h>
#include <llvm/ADT/DenseSet.h>
#include <mutex>
#include <stdexcept> #include <stdexcept>
using namespace llvm; using namespace llvm;
@ -131,14 +134,12 @@ void Reflect(Writer& visitor, std::string_view& data) {
visitor.String(&data[0], (rapidjson::SizeType)data.size()); visitor.String(&data[0], (rapidjson::SizeType)data.size());
} }
void Reflect(Reader& visitor, NtString& value) { void Reflect(Reader& vis, const char*& v) {
if (!visitor.IsString()) const char* str = vis.GetString();
throw std::invalid_argument("std::string"); v = ccls::Intern(str);
value = visitor.GetString();
} }
void Reflect(Writer& visitor, NtString& value) { void Reflect(Writer& vis, const char*& v) {
const char* s = value.c_str(); vis.String(v);
visitor.String(s ? s : "");
} }
void Reflect(Reader& visitor, JsonNull& value) { void Reflect(Reader& visitor, JsonNull& value) {
@ -223,9 +224,9 @@ void ReflectHoverAndComments(Reader& visitor, Def& def) {
template <typename Def> template <typename Def>
void ReflectHoverAndComments(Writer& visitor, Def& def) { void ReflectHoverAndComments(Writer& visitor, Def& def) {
// Don't emit empty hover and comments in JSON test mode. // Don't emit empty hover and comments in JSON test mode.
if (!gTestOutputMode || !def.hover.empty()) if (!gTestOutputMode || def.hover[0])
ReflectMember(visitor, "hover", def.hover); ReflectMember(visitor, "hover", def.hover);
if (!gTestOutputMode || !def.comments.empty()) if (!gTestOutputMode || def.comments[0])
ReflectMember(visitor, "comments", def.comments); ReflectMember(visitor, "comments", def.comments);
} }
@ -234,7 +235,7 @@ void ReflectShortName(Reader& visitor, Def& def) {
if (gTestOutputMode) { if (gTestOutputMode) {
std::string short_name; std::string short_name;
ReflectMember(visitor, "short_name", short_name); ReflectMember(visitor, "short_name", short_name);
def.short_name_offset = def.detailed_name.find(short_name); def.short_name_offset = std::string_view(def.detailed_name).find(short_name);
assert(def.short_name_offset != std::string::npos); assert(def.short_name_offset != std::string::npos);
def.short_name_size = short_name.size(); def.short_name_size = short_name.size();
} else { } else {
@ -246,8 +247,8 @@ void ReflectShortName(Reader& visitor, Def& def) {
template <typename Def> template <typename Def>
void ReflectShortName(Writer& visitor, Def& def) { void ReflectShortName(Writer& visitor, Def& def) {
if (gTestOutputMode) { if (gTestOutputMode) {
std::string short_name( std::string_view short_name(def.detailed_name + def.short_name_offset,
def.detailed_name.substr(def.short_name_offset, def.short_name_size)); def.short_name_size);
ReflectMember(visitor, "short_name", short_name); ReflectMember(visitor, "short_name", short_name);
} else { } else {
ReflectMember(visitor, "short_name_offset", def.short_name_offset); 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) { std::string Serialize(SerializeFormat format, IndexFile& file) {
switch (format) { switch (format) {
case SerializeFormat::Binary: { case SerializeFormat::Binary: {
@ -451,3 +467,4 @@ std::unique_ptr<IndexFile> Deserialize(
file->path = path; file->path = path;
return file; return file;
} }
}

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "maybe.h" #include "maybe.h"
#include "nt_string.h"
#include <llvm/Support/Compiler.h> #include <llvm/Support/Compiler.h>
@ -42,7 +41,7 @@ class Reader {
virtual int64_t GetInt64() = 0; virtual int64_t GetInt64() = 0;
virtual uint64_t GetUInt64() = 0; virtual uint64_t GetUInt64() = 0;
virtual double GetDouble() = 0; virtual double GetDouble() = 0;
virtual std::string GetString() = 0; virtual const char* GetString() = 0;
virtual bool HasMember(const char* x) = 0; virtual bool HasMember(const char* x) = 0;
virtual std::unique_ptr<Reader> operator[](const char* x) = 0; virtual std::unique_ptr<Reader> operator[](const char* x) = 0;
@ -180,8 +179,8 @@ void Reflect(Writer& visitor, std::string& value);
void Reflect(Reader& visitor, std::string_view& view); void Reflect(Reader& visitor, std::string_view& view);
void Reflect(Writer& visitor, std::string_view& view); void Reflect(Writer& visitor, std::string_view& view);
void Reflect(Reader& visitor, NtString& value); void Reflect(Reader& vis, const char*& v);
void Reflect(Writer& visitor, NtString& value); void Reflect(Writer& vis, const char*& v);
void Reflect(Reader& visitor, JsonNull& value); void Reflect(Reader& visitor, JsonNull& value);
void Reflect(Writer& visitor, JsonNull& value); void Reflect(Writer& visitor, JsonNull& value);
@ -322,6 +321,8 @@ void ReflectMember(Writer& vis, const char* name, T& v) {
// API // API
namespace ccls {
const char* Intern(const std::string& str);
std::string Serialize(SerializeFormat format, IndexFile& file); std::string Serialize(SerializeFormat format, IndexFile& file);
std::unique_ptr<IndexFile> Deserialize( std::unique_ptr<IndexFile> Deserialize(
SerializeFormat format, SerializeFormat format,
@ -329,3 +330,4 @@ std::unique_ptr<IndexFile> Deserialize(
const std::string& serialized_index_content, const std::string& serialized_index_content,
const std::string& file_content, const std::string& file_content,
std::optional<int> expected_version); std::optional<int> expected_version);
}

View File

@ -52,13 +52,12 @@ class BinaryReader : public Reader {
uint32_t GetUInt32() override { return VarUInt(); } uint32_t GetUInt32() override { return VarUInt(); }
uint64_t GetUInt64() override { return VarUInt(); } uint64_t GetUInt64() override { return VarUInt(); }
double GetDouble() override { return Get<double>(); } double GetDouble() override { return Get<double>(); }
std::string GetString() override { const char* GetString() override {
if (auto n = VarUInt()) { const char* ret = p_;
std::string ret(p_, n); while (*p_)
p_ += n; p_++;
return ret; p_++;
} return ret;
return "";
} }
bool HasMember(const char* x) override { return true; } bool HasMember(const char* x) override { return true; }
@ -118,9 +117,8 @@ class BinaryWriter : public Writer {
void Double(double x) override { Pack(x); } void Double(double x) override { Pack(x); }
void String(const char* x) override { String(x, strlen(x)); } void String(const char* x) override { String(x, strlen(x)); }
void String(const char* x, size_t len) override { void String(const char* x, size_t len) override {
VarUInt(len);
auto i = buf_.size(); auto i = buf_.size();
buf_.resize(i + len); buf_.resize(i + len + 1);
memcpy(buf_.data() + i, x, len); memcpy(buf_.data() + i, x, len);
} }
void StartArray(size_t n) override { VarUInt(n); } void StartArray(size_t n) override { VarUInt(n); }

View File

@ -29,7 +29,7 @@ class JsonReader : public Reader {
uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); } uint32_t GetUInt32() override { return uint32_t(m_->GetUint64()); }
uint64_t GetUInt64() override { return m_->GetUint64(); } uint64_t GetUInt64() override { return m_->GetUint64(); }
double GetDouble() override { return m_->GetDouble(); } double GetDouble() override { return m_->GetDouble(); }
std::string GetString() override { return m_->GetString(); } const char* GetString() override { return m_->GetString(); }
bool HasMember(const char* x) override { return m_->HasMember(x); } bool HasMember(const char* x) override { return m_->HasMember(x); }
std::unique_ptr<Reader> operator[](const char* x) override { std::unique_ptr<Reader> operator[](const char* x) override {

View File

@ -191,10 +191,10 @@ void DiffDocuments(std::string path,
void VerifySerializeToFrom(IndexFile* file) { void VerifySerializeToFrom(IndexFile* file) {
std::string expected = file->ToString(); 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 = std::unique_ptr<IndexFile> result =
Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>", ccls::Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
std::nullopt /*expected_version*/); std::nullopt /*expected_version*/);
std::string actual = result->ToString(); std::string actual = result->ToString();
if (expected != actual) { if (expected != actual) {
fprintf(stderr, "Serialization failure\n"); fprintf(stderr, "Serialization failure\n");