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:
Fangrui Song 2018-09-02 14:51:25 -07:00
parent 1ab0d492b7
commit a8bb605d4a
7 changed files with 78 additions and 64 deletions

View File

@ -137,8 +137,8 @@ struct Config {
// xxx: at most every xxx milliseconds // xxx: at most every xxx milliseconds
int frequencyMs = 0; int frequencyMs = 0;
// If true, diagnostics from a full document parse will be reported. // If true, diagnostics will be reported in textDocument/didOpen.
bool onParse = true; bool onOpen = true;
// If true, diagnostics from typing will be reported. // If true, diagnostics from typing will be reported.
bool onType = true; bool onType = true;
@ -159,14 +159,6 @@ struct Config {
} highlight; } highlight;
struct Index { 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 // 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 // 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. // 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. // If false, the indexer will be disabled.
bool enabled = true; 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. // Allow indexing on textDocument/didChange.
// May be too slow for big projects, so it is off by default. // May be too slow for big projects, so it is off by default.
bool onDidChange = false; bool onDidChange = false;
@ -226,12 +221,11 @@ MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, dropOldRequests,
detailedLabel, filterAndSort, includeBlacklist, detailedLabel, filterAndSort, includeBlacklist,
includeMaxPathSize, includeSuffixWhitelist, includeMaxPathSize, includeSuffixWhitelist,
includeWhitelist); includeWhitelist);
MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onParse, MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onOpen,
onType, whitelist) onType, whitelist)
MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist) MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist)
MAKE_REFLECT_STRUCT(Config::Index, attributeMakeCallsToCtor, blacklist, MAKE_REFLECT_STRUCT(Config::Index, blacklist, comments, enabled, multiVersion,
comments, enabled, onDidChange, reparseForDependency, onDidChange, reparseForDependency, threads, whitelist);
threads, whitelist);
MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort); MAKE_REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum); MAKE_REFLECT_STRUCT(Config::Xref, container, maxNum);
MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand, MAKE_REFLECT_STRUCT(Config, compilationDatabaseCommand,

View File

@ -48,9 +48,7 @@ struct IndexParam {
IndexParam(FileConsumer *file_consumer) : file_consumer(file_consumer) {} IndexParam(FileConsumer *file_consumer) : file_consumer(file_consumer) {}
IndexFile *ConsumeFile(const FileEntry &File) { void SeenFile(const FileEntry &File) {
IndexFile *db = file_consumer->TryConsumeFile(File, &file_contents);
// If this is the first time we have seen the file (ignoring if we are // If this is the first time we have seen the file (ignoring if we are
// generating an index for it): // generating an index for it):
auto [it, inserted] = SeenUniqueID.try_emplace(File.getUniqueID()); auto [it, inserted] = SeenUniqueID.try_emplace(File.getUniqueID());
@ -65,8 +63,11 @@ struct IndexParam {
if (write_time) if (write_time)
file2write_time[file_name] = *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; 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 { Role role) const {
if (!DC) if (!DC)
return Use{{range, 0, SymbolKind::File, role}}; return {{range, 0, SymbolKind::File, role}, lid};
const Decl *D = cast<Decl>(DC); const Decl *D = cast<Decl>(DC);
switch (GetSymbolKind(D)) { switch (GetSymbolKind(D)) {
case SymbolKind::Func: 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: 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: 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: 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, void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
SourceLocation Spell) const { SourceLocation Spell) const {
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell)); const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
if (!FE) if (!FE)
return; return;
auto UID = FE->getUniqueID(); int lid = GetFileLID(db, SM, *FE);
auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID); if (lid < 0)
if (inserted) { return;
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;
it->second.second = Path.str();
}
Range spell = Range spell =
FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, 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) { switch (kind) {
case SymbolKind::Func: case SymbolKind::Func:
db->ToFunc(usr).uses.push_back(use); db->ToFunc(usr).uses.push_back(use);
@ -615,15 +622,26 @@ public:
FE = SM.getFileEntryForID(LocFID); FE = SM.getFileEntryForID(LocFID);
if (!FE) if (!FE)
return true; return true;
IndexFile *db = param.ConsumeFile(*FE); int lid = -1;
if (!db) IndexFile *db;
return true; 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 Decl *OrigD = ASTNode.OrigD;
const DeclContext *SemDC = OrigD->getDeclContext(); const DeclContext *SemDC = OrigD->getDeclContext();
const DeclContext *LexDC = ASTNode.ContainerDC; const DeclContext *LexDC = ASTNode.ContainerDC;
Role role = static_cast<Role>(Roles); 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_decl = Roles & uint32_t(index::SymbolRole::Declaration);
bool is_def = Roles & uint32_t(index::SymbolRole::Definition); bool is_def = Roles & uint32_t(index::SymbolRole::Definition);
@ -638,18 +656,18 @@ public:
auto do_def_decl = [&](auto *entity) { auto do_def_decl = [&](auto *entity) {
if (is_def) { if (is_def) {
entity->def.spell = GetUse(db, loc, SemDC, role); entity->def.spell = GetUse(db, lid, loc, SemDC, role);
SourceRange R = OrigD->getSourceRange(); SourceRange R = OrigD->getSourceRange();
entity->def.extent = entity->def.extent =
GetUse(db, GetUse(db, lid,
R.getBegin().isFileID() R.getBegin().isFileID()
? FromTokenRange(SM, Lang, OrigD->getSourceRange()) ? FromTokenRange(SM, Lang, OrigD->getSourceRange())
: loc, : loc,
LexDC, Role::None); LexDC, Role::None);
} else if (is_decl) { } else if (is_decl) {
entity->declarations.push_back(GetUse(db, loc, LexDC, role)); entity->declarations.push_back(GetUse(db, lid, loc, LexDC, role));
} else { } else {
entity->uses.push_back(GetUse(db, loc, LexDC, role)); entity->uses.push_back(GetUse(db, lid, loc, LexDC, role));
return; return;
} }
if (entity->def.comments[0] == '\0' && g_config->index.comments) if (entity->def.comments[0] == '\0' && g_config->index.comments)
@ -735,10 +753,11 @@ public:
if (SM.getFileID(R1.getBegin()) == LocFID) { if (SM.getFileID(R1.getBegin()) == LocFID) {
IndexType &type1 = db->ToType(usr1); IndexType &type1 = db->ToType(usr1);
SourceLocation L1 = D1->getLocation(); SourceLocation L1 = D1->getLocation();
type1.def.spell = GetUse(db, FromTokenRange(SM, Lang, {L1, L1}), type1.def.spell =
SemDC, Role::Definition); GetUse(db, lid, FromTokenRange(SM, Lang, {L1, L1}), SemDC,
type1.def.extent = Role::Definition);
GetUse(db, FromTokenRange(SM, Lang, R1), LexDC, Role::None); type1.def.extent = GetUse(db, lid, FromTokenRange(SM, Lang, R1),
LexDC, Role::None);
type1.def.detailed_name = Intern(info1->short_name); type1.def.detailed_name = Intern(info1->short_name);
type1.def.short_name_size = int16_t(info1->short_name.size()); type1.def.short_name_size = int16_t(info1->short_name.size());
type1.def.kind = lsSymbolKind::TypeParameter; type1.def.kind = lsSymbolKind::TypeParameter;
@ -753,10 +772,10 @@ public:
// e.g. lambda parameter // e.g. lambda parameter
SourceLocation L = OrigD->getLocation(); SourceLocation L = OrigD->getLocation();
if (SM.getFileID(L) == LocFID) { if (SM.getFileID(L) == LocFID) {
var->def.spell = GetUse(db, FromTokenRange(SM, Lang, {L, L}), SemDC, var->def.spell = GetUse(db, lid, FromTokenRange(SM, Lang, {L, L}),
Role::Definition); SemDC, Role::Definition);
var->def.extent = var->def.extent =
GetUse(db, FromTokenRange(SM, Lang, OrigD->getSourceRange()), GetUse(db, lid, FromTokenRange(SM, Lang, OrigD->getSourceRange()),
LexDC, Role::None); LexDC, Role::None);
} }
} }
@ -853,10 +872,10 @@ public:
std::tie(RD, offset) = Stack.back(); std::tie(RD, offset) = Stack.back();
Stack.pop_back(); Stack.pop_back();
if (!RD->isCompleteDefinition() || RD->isDependentType() || if (!RD->isCompleteDefinition() || RD->isDependentType() ||
!ValidateRecord(RD)) RD->isInvalidDecl() || !ValidateRecord(RD))
offset = -1; offset = -1;
for (FieldDecl *FD : RD->fields()) { 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()) if (FD->getIdentifier())
type->def.vars.emplace_back(GetUsr(FD), offset1); type->def.vars.emplace_back(GetUsr(FD), offset1);
else if (const auto *RT1 = FD->getType()->getAs<RecordType>()) { else if (const auto *RT1 = FD->getType()->getAs<RecordType>()) {
@ -913,7 +932,8 @@ public:
SourceLocation L1 = TSI->getTypeLoc().getBeginLoc(); SourceLocation L1 = TSI->getTypeLoc().getBeginLoc();
if (SM.getFileID(L1) == LocFID) { if (SM.getFileID(L1) == LocFID) {
Range loc1 = FromTokenRange(SM, Lang, {L1, L1}); 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) if (!FE)
return; return;
if (IndexFile *db = param.ConsumeFile(*FE)) { if (IndexFile *db = param.ConsumeFile(*FE)) {
auto [Name, usr] = GetMacro(Tok); IndexVar &var = db->ToVar(GetMacro(Tok).second);
IndexVar &var = db->ToVar(usr);
var.uses.push_back( var.uses.push_back(
{{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0, {{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
SymbolKind::File, Role::Dynamic}}); SymbolKind::File, Role::Dynamic}});

View File

@ -229,7 +229,7 @@ struct IndexFile {
std::string path; std::string path;
std::vector<std::string> args; std::vector<std::string> args;
int64_t last_write_time = 0; 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. // uid2lid_and_path is used to generate lid2path, but not serialized.
std::unordered_map<llvm::sys::fs::UniqueID, std::pair<int, std::string>> std::unordered_map<llvm::sys::fs::UniqueID, std::pair<int, std::string>>

View File

@ -10,7 +10,7 @@
// Used to identify the language at a file level. The ordering is important, as // 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 // a file previously identified as `C`, will be changed to `Cpp` if it
// encounters a c++ declaration. // 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); MAKE_REFLECT_TYPE_PROXY(LanguageId);
LanguageId SourceFileLanguage(std::string_view path); LanguageId SourceFileLanguage(std::string_view path);

View File

@ -66,7 +66,7 @@ struct Handler_TextDocumentDidOpen
} }
clang_complete->NotifyView(path); clang_complete->NotifyView(path);
if (g_config->diagnostics.onParse) if (g_config->diagnostics.onOpen)
clang_complete->DiagnosticsUpdate({params.textDocument.uri}); clang_complete->DiagnosticsUpdate({params.textDocument.uri});
} }
}; };

View File

@ -17,7 +17,7 @@
namespace { 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) if (ref.kind == SymbolKind::File)
ref.usr = file_id; ref.usr = file_id;
} }

View File

@ -5,13 +5,14 @@
#include "serializer.h" #include "serializer.h"
#include <assert.h> #include <string.h>
class BinaryReader : public Reader { class BinaryReader : public Reader {
const char *p_; const char *p_;
template <typename T> T Get() { template <typename T> T Get() {
auto ret = *reinterpret_cast<const T *>(p_); T ret;
memcpy(&ret, p_, sizeof(T));
p_ += sizeof(T); p_ += sizeof(T);
return ret; return ret;
} }
@ -77,7 +78,7 @@ class BinaryWriter : public Writer {
template <typename T> void Pack(T x) { template <typename T> void Pack(T x) {
auto i = buf_.size(); auto i = buf_.size();
buf_.resize(i + sizeof(x)); buf_.resize(i + sizeof(x));
*reinterpret_cast<T *>(buf_.data() + i) = x; memcpy(buf_.data() + i, &x, sizeof(x));
} }
void VarUInt(uint64_t n) { void VarUInt(uint64_t n) {