From a8bb605d4a1f34d5678d2f643a5407756c54dca7 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 2 Sep 2018 14:51:25 -0700 Subject: [PATCH] Fix unaligned load/store; add index.multiVersion prototype, rename index.onParse to index.OnOpen Don't call getFieldOffset() on RD->isInvalidDecl() --- src/config.h | 22 ++---- src/indexer.cc | 105 ++++++++++++++++----------- src/indexer.h | 2 +- src/language.h | 2 +- src/messages/textDocument_didOpen.cc | 2 +- src/query.cc | 2 +- src/serializers/binary.h | 7 +- 7 files changed, 78 insertions(+), 64 deletions(-) diff --git a/src/config.h b/src/config.h index 63bdc6cb..89c99eba 100644 --- a/src/config.h +++ b/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, diff --git a/src/indexer.cc b/src/indexer.cc index 7e8d216c..a9db95dd 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -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(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)) - return; - it->second.second = Path.str(); - } + int lid = GetFileLID(db, SM, *FE); + if (lid < 0) + return; 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); - if (!db) - return true; + 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(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()) { @@ -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}}); diff --git a/src/indexer.h b/src/indexer.h index c80afe69..74b404ec 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -229,7 +229,7 @@ struct IndexFile { std::string path; std::vector 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> diff --git a/src/language.h b/src/language.h index 5cbcf2b6..94dc2697 100644 --- a/src/language.h +++ b/src/language.h @@ -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); diff --git a/src/messages/textDocument_didOpen.cc b/src/messages/textDocument_didOpen.cc index 1f9f8e90..16d5c503 100644 --- a/src/messages/textDocument_didOpen.cc +++ b/src/messages/textDocument_didOpen.cc @@ -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}); } }; diff --git a/src/query.cc b/src/query.cc index b86c490a..010806dd 100644 --- a/src/query.cc +++ b/src/query.cc @@ -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; } diff --git a/src/serializers/binary.h b/src/serializers/binary.h index 5b56dd05..d35dd9f2 100644 --- a/src/serializers/binary.h +++ b/src/serializers/binary.h @@ -5,13 +5,14 @@ #include "serializer.h" -#include +#include class BinaryReader : public Reader { const char *p_; template T Get() { - auto ret = *reinterpret_cast(p_); + T ret; + memcpy(&ret, p_, sizeof(T)); p_ += sizeof(T); return ret; } @@ -77,7 +78,7 @@ class BinaryWriter : public Writer { template void Pack(T x) { auto i = buf_.size(); buf_.resize(i + sizeof(x)); - *reinterpret_cast(buf_.data() + i) = x; + memcpy(buf_.data() + i, &x, sizeof(x)); } void VarUInt(uint64_t n) {