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
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,

View File

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

View File

@ -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>>

View File

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

View File

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

View File

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

View File

@ -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) {