mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 09:05:10 +00:00
Fix unaligned load/store; add index.multiVersion prototype, rename index.onParse to index.OnOpen
Don't call getFieldOffset() on RD->isInvalidDecl()
This commit is contained in:
parent
1ab0d492b7
commit
a8bb605d4a
22
src/config.h
22
src/config.h
@ -137,8 +137,8 @@ struct Config {
|
||||
// xxx: at most every xxx milliseconds
|
||||
int frequencyMs = 0;
|
||||
|
||||
// If true, diagnostics from a full document parse will be reported.
|
||||
bool onParse = true;
|
||||
// If true, diagnostics will be reported in textDocument/didOpen.
|
||||
bool onOpen = true;
|
||||
|
||||
// If true, diagnostics from typing will be reported.
|
||||
bool onType = true;
|
||||
@ -159,14 +159,6 @@ struct Config {
|
||||
} highlight;
|
||||
|
||||
struct Index {
|
||||
// Attempt to convert calls of make* functions to constructors based on
|
||||
// hueristics.
|
||||
//
|
||||
// For example, this will show constructor calls for std::make_unique
|
||||
// invocations. Specifically, ccls will try to attribute a ctor call
|
||||
// whenever the function name starts with make (ignoring case).
|
||||
bool attributeMakeCallsToCtor = true;
|
||||
|
||||
// If a translation unit's absolute path matches any EMCAScript regex in the
|
||||
// whitelist, or does not match any regex in the blacklist, it will be
|
||||
// indexed. To only index files in the whitelist, add ".*" to the blacklist.
|
||||
@ -184,6 +176,9 @@ struct Config {
|
||||
// If false, the indexer will be disabled.
|
||||
bool enabled = true;
|
||||
|
||||
// If not 0, a file will be indexed in each tranlation unit that includes it.
|
||||
int multiVersion = 0;
|
||||
|
||||
// Allow indexing on textDocument/didChange.
|
||||
// May be too slow for big projects, so it is off by default.
|
||||
bool onDidChange = false;
|
||||
@ -226,12 +221,11 @@ MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, dropOldRequests,
|
||||
detailedLabel, filterAndSort, includeBlacklist,
|
||||
includeMaxPathSize, includeSuffixWhitelist,
|
||||
includeWhitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onParse,
|
||||
MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onOpen,
|
||||
onType, whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist)
|
||||
MAKE_REFLECT_STRUCT(Config::Index, attributeMakeCallsToCtor, blacklist,
|
||||
comments, enabled, onDidChange, reparseForDependency,
|
||||
threads, whitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::Index, blacklist, comments, enabled, multiVersion,
|
||||
onDidChange, reparseForDependency, threads, whitelist);
|
||||
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
|
||||
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
|
||||
MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,
|
||||
|
@ -48,9 +48,7 @@ struct IndexParam {
|
||||
|
||||
IndexParam(FileConsumer *file_consumer) : file_consumer(file_consumer) {}
|
||||
|
||||
IndexFile *ConsumeFile(const FileEntry &File) {
|
||||
IndexFile *db = file_consumer->TryConsumeFile(File, &file_contents);
|
||||
|
||||
void SeenFile(const FileEntry &File) {
|
||||
// If this is the first time we have seen the file (ignoring if we are
|
||||
// generating an index for it):
|
||||
auto [it, inserted] = SeenUniqueID.try_emplace(File.getUniqueID());
|
||||
@ -65,8 +63,11 @@ struct IndexParam {
|
||||
if (write_time)
|
||||
file2write_time[file_name] = *write_time;
|
||||
}
|
||||
}
|
||||
|
||||
return db;
|
||||
IndexFile *ConsumeFile(const FileEntry &File) {
|
||||
SeenFile(File);
|
||||
return file_consumer->TryConsumeFile(File, &file_contents);
|
||||
}
|
||||
};
|
||||
|
||||
@ -392,20 +393,20 @@ public:
|
||||
return it->second.usr;
|
||||
}
|
||||
|
||||
Use GetUse(IndexFile *db, Range range, const DeclContext *DC,
|
||||
Use GetUse(IndexFile *db, int lid, Range range, const DeclContext *DC,
|
||||
Role role) const {
|
||||
if (!DC)
|
||||
return Use{{range, 0, SymbolKind::File, role}};
|
||||
return {{range, 0, SymbolKind::File, role}, lid};
|
||||
const Decl *D = cast<Decl>(DC);
|
||||
switch (GetSymbolKind(D)) {
|
||||
case SymbolKind::Func:
|
||||
return Use{{range, db->ToFunc(GetUsr(D)).usr, SymbolKind::Func, role}};
|
||||
return {{range, db->ToFunc(GetUsr(D)).usr, SymbolKind::Func, role}, lid};
|
||||
case SymbolKind::Type:
|
||||
return Use{{range, db->ToType(GetUsr(D)).usr, SymbolKind::Type, role}};
|
||||
return {{range, db->ToType(GetUsr(D)).usr, SymbolKind::Type, role}, lid};
|
||||
case SymbolKind::Var:
|
||||
return Use{{range, db->ToVar(GetUsr(D)).usr, SymbolKind::Var, role}};
|
||||
return {{range, db->ToVar(GetUsr(D)).usr, SymbolKind::Var, role}, lid};
|
||||
default:
|
||||
return Use{{range, 0, SymbolKind::File, role}};
|
||||
return {{range, 0, SymbolKind::File, role}, lid};
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,26 +536,32 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static int GetFileLID(IndexFile *db, SourceManager &SM, const FileEntry &FE) {
|
||||
auto [it, inserted] = db->uid2lid_and_path.try_emplace(FE.getUniqueID());
|
||||
if (inserted) {
|
||||
it->second.first = db->uid2lid_and_path.size() - 1;
|
||||
SmallString<256> Path = FE.tryGetRealPathName();
|
||||
if (Path.empty())
|
||||
Path = FE.getName();
|
||||
if (!llvm::sys::path::is_absolute(Path) &&
|
||||
!SM.getFileManager().makeAbsolutePath(Path))
|
||||
return -1;
|
||||
it->second.second = Path.str();
|
||||
}
|
||||
return it->second.first;
|
||||
}
|
||||
|
||||
void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
|
||||
SourceLocation Spell) const {
|
||||
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
|
||||
if (!FE)
|
||||
return;
|
||||
auto UID = FE->getUniqueID();
|
||||
auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID);
|
||||
if (inserted) {
|
||||
it->second.first = db->uid2lid_and_path.size() - 1;
|
||||
SmallString<256> Path = FE->tryGetRealPathName();
|
||||
if (Path.empty())
|
||||
Path = FE->getName();
|
||||
if (!llvm::sys::path::is_absolute(Path) &&
|
||||
!SM.getFileManager().makeAbsolutePath(Path))
|
||||
int lid = GetFileLID(db, SM, *FE);
|
||||
if (lid < 0)
|
||||
return;
|
||||
it->second.second = Path.str();
|
||||
}
|
||||
Range spell =
|
||||
FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, Spell));
|
||||
Use use{{spell, 0, SymbolKind::File, Role::Dynamic}, it->second.first};
|
||||
Use use{{spell, 0, SymbolKind::File, Role::Dynamic}, lid};
|
||||
switch (kind) {
|
||||
case SymbolKind::Func:
|
||||
db->ToFunc(usr).uses.push_back(use);
|
||||
@ -615,15 +622,26 @@ public:
|
||||
FE = SM.getFileEntryForID(LocFID);
|
||||
if (!FE)
|
||||
return true;
|
||||
IndexFile *db = param.ConsumeFile(*FE);
|
||||
int lid = -1;
|
||||
IndexFile *db;
|
||||
if (g_config->index.multiVersion) {
|
||||
db = param.ConsumeFile(*SM.getFileEntryForID(SM.getMainFileID()));
|
||||
if (!db)
|
||||
return true;
|
||||
param.SeenFile(*FE);
|
||||
if (!SM.isInMainFile(R.getBegin()))
|
||||
lid = GetFileLID(db, SM, *FE);
|
||||
} else {
|
||||
db = param.ConsumeFile(*FE);
|
||||
if (!db)
|
||||
return true;
|
||||
}
|
||||
|
||||
const Decl *OrigD = ASTNode.OrigD;
|
||||
const DeclContext *SemDC = OrigD->getDeclContext();
|
||||
const DeclContext *LexDC = ASTNode.ContainerDC;
|
||||
Role role = static_cast<Role>(Roles);
|
||||
db->language = std::max(db->language, GetDeclLanguage(OrigD));
|
||||
db->language = LanguageId((int)db->language | (int)GetDeclLanguage(OrigD));
|
||||
|
||||
bool is_decl = Roles & uint32_t(index::SymbolRole::Declaration);
|
||||
bool is_def = Roles & uint32_t(index::SymbolRole::Definition);
|
||||
@ -638,18 +656,18 @@ public:
|
||||
|
||||
auto do_def_decl = [&](auto *entity) {
|
||||
if (is_def) {
|
||||
entity->def.spell = GetUse(db, loc, SemDC, role);
|
||||
entity->def.spell = GetUse(db, lid, loc, SemDC, role);
|
||||
SourceRange R = OrigD->getSourceRange();
|
||||
entity->def.extent =
|
||||
GetUse(db,
|
||||
GetUse(db, lid,
|
||||
R.getBegin().isFileID()
|
||||
? FromTokenRange(SM, Lang, OrigD->getSourceRange())
|
||||
: loc,
|
||||
LexDC, Role::None);
|
||||
} else if (is_decl) {
|
||||
entity->declarations.push_back(GetUse(db, loc, LexDC, role));
|
||||
entity->declarations.push_back(GetUse(db, lid, loc, LexDC, role));
|
||||
} else {
|
||||
entity->uses.push_back(GetUse(db, loc, LexDC, role));
|
||||
entity->uses.push_back(GetUse(db, lid, loc, LexDC, role));
|
||||
return;
|
||||
}
|
||||
if (entity->def.comments[0] == '\0' && g_config->index.comments)
|
||||
@ -735,10 +753,11 @@ public:
|
||||
if (SM.getFileID(R1.getBegin()) == LocFID) {
|
||||
IndexType &type1 = db->ToType(usr1);
|
||||
SourceLocation L1 = D1->getLocation();
|
||||
type1.def.spell = GetUse(db, FromTokenRange(SM, Lang, {L1, L1}),
|
||||
SemDC, Role::Definition);
|
||||
type1.def.extent =
|
||||
GetUse(db, FromTokenRange(SM, Lang, R1), LexDC, Role::None);
|
||||
type1.def.spell =
|
||||
GetUse(db, lid, FromTokenRange(SM, Lang, {L1, L1}), SemDC,
|
||||
Role::Definition);
|
||||
type1.def.extent = GetUse(db, lid, FromTokenRange(SM, Lang, R1),
|
||||
LexDC, Role::None);
|
||||
type1.def.detailed_name = Intern(info1->short_name);
|
||||
type1.def.short_name_size = int16_t(info1->short_name.size());
|
||||
type1.def.kind = lsSymbolKind::TypeParameter;
|
||||
@ -753,10 +772,10 @@ public:
|
||||
// e.g. lambda parameter
|
||||
SourceLocation L = OrigD->getLocation();
|
||||
if (SM.getFileID(L) == LocFID) {
|
||||
var->def.spell = GetUse(db, FromTokenRange(SM, Lang, {L, L}), SemDC,
|
||||
Role::Definition);
|
||||
var->def.spell = GetUse(db, lid, FromTokenRange(SM, Lang, {L, L}),
|
||||
SemDC, Role::Definition);
|
||||
var->def.extent =
|
||||
GetUse(db, FromTokenRange(SM, Lang, OrigD->getSourceRange()),
|
||||
GetUse(db, lid, FromTokenRange(SM, Lang, OrigD->getSourceRange()),
|
||||
LexDC, Role::None);
|
||||
}
|
||||
}
|
||||
@ -853,10 +872,10 @@ public:
|
||||
std::tie(RD, offset) = Stack.back();
|
||||
Stack.pop_back();
|
||||
if (!RD->isCompleteDefinition() || RD->isDependentType() ||
|
||||
!ValidateRecord(RD))
|
||||
RD->isInvalidDecl() || !ValidateRecord(RD))
|
||||
offset = -1;
|
||||
for (FieldDecl *FD : RD->fields()) {
|
||||
int offset1 = offset >= 0 ? offset + Ctx->getFieldOffset(FD) : -1;
|
||||
int offset1 = offset < 0 ? -1 : offset + Ctx->getFieldOffset(FD);
|
||||
if (FD->getIdentifier())
|
||||
type->def.vars.emplace_back(GetUsr(FD), offset1);
|
||||
else if (const auto *RT1 = FD->getType()->getAs<RecordType>()) {
|
||||
@ -913,7 +932,8 @@ public:
|
||||
SourceLocation L1 = TSI->getTypeLoc().getBeginLoc();
|
||||
if (SM.getFileID(L1) == LocFID) {
|
||||
Range loc1 = FromTokenRange(SM, Lang, {L1, L1});
|
||||
type1.uses.push_back(GetUse(db, loc1, LexDC, Role::Reference));
|
||||
type1.uses.push_back(
|
||||
GetUse(db, lid, loc1, LexDC, Role::Reference));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1066,8 +1086,7 @@ public:
|
||||
if (!FE)
|
||||
return;
|
||||
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
||||
auto [Name, usr] = GetMacro(Tok);
|
||||
IndexVar &var = db->ToVar(usr);
|
||||
IndexVar &var = db->ToVar(GetMacro(Tok).second);
|
||||
var.uses.push_back(
|
||||
{{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
|
||||
SymbolKind::File, Role::Dynamic}});
|
||||
|
@ -229,7 +229,7 @@ struct IndexFile {
|
||||
std::string path;
|
||||
std::vector<std::string> args;
|
||||
int64_t last_write_time = 0;
|
||||
LanguageId language = LanguageId::Unknown;
|
||||
LanguageId language = LanguageId::C;
|
||||
|
||||
// uid2lid_and_path is used to generate lid2path, but not serialized.
|
||||
std::unordered_map<llvm::sys::fs::UniqueID, std::pair<int, std::string>>
|
||||
|
@ -10,7 +10,7 @@
|
||||
// Used to identify the language at a file level. The ordering is important, as
|
||||
// a file previously identified as `C`, will be changed to `Cpp` if it
|
||||
// encounters a c++ declaration.
|
||||
enum class LanguageId { Unknown = 0, C = 1, Cpp = 2, ObjC = 3, ObjCpp = 4 };
|
||||
enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3 };
|
||||
MAKE_REFLECT_TYPE_PROXY(LanguageId);
|
||||
|
||||
LanguageId SourceFileLanguage(std::string_view path);
|
||||
|
@ -66,7 +66,7 @@ struct Handler_TextDocumentDidOpen
|
||||
}
|
||||
|
||||
clang_complete->NotifyView(path);
|
||||
if (g_config->diagnostics.onParse)
|
||||
if (g_config->diagnostics.onOpen)
|
||||
clang_complete->DiagnosticsUpdate({params.textDocument.uri});
|
||||
}
|
||||
};
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
namespace {
|
||||
|
||||
void AssignFileId(const Lid2file_id &, int file_id, SymbolRef &ref) {
|
||||
void AssignFileId(const Lid2file_id &lid2file_id, int file_id, SymbolRef &ref) {
|
||||
if (ref.kind == SymbolKind::File)
|
||||
ref.usr = file_id;
|
||||
}
|
||||
|
@ -5,13 +5,14 @@
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
class BinaryReader : public Reader {
|
||||
const char *p_;
|
||||
|
||||
template <typename T> T Get() {
|
||||
auto ret = *reinterpret_cast<const T *>(p_);
|
||||
T ret;
|
||||
memcpy(&ret, p_, sizeof(T));
|
||||
p_ += sizeof(T);
|
||||
return ret;
|
||||
}
|
||||
@ -77,7 +78,7 @@ class BinaryWriter : public Writer {
|
||||
template <typename T> void Pack(T x) {
|
||||
auto i = buf_.size();
|
||||
buf_.resize(i + sizeof(x));
|
||||
*reinterpret_cast<T *>(buf_.data() + i) = x;
|
||||
memcpy(buf_.data() + i, &x, sizeof(x));
|
||||
}
|
||||
|
||||
void VarUInt(uint64_t n) {
|
||||
|
Loading…
Reference in New Issue
Block a user