indexer: llvm::sys::fs::UniqueID -> clang::FileID

Fix a minor issue that an empty included file is not recorded.

Note, we need to skip invalid uid2lid_and_path because
otherwise lid2path may contain invalid entries with lid: 0,
which will cause the file entry with file_id 0 to have an empty path.
This commit is contained in:
Fangrui Song 2019-08-21 23:46:02 -07:00
parent 97af6fb889
commit 5422afe35a
4 changed files with 69 additions and 89 deletions

View File

@ -41,42 +41,30 @@ static Pos decomposed2LineAndCol(const SourceManager &sm,
} }
Range fromCharSourceRange(const SourceManager &sm, const LangOptions &lang, Range fromCharSourceRange(const SourceManager &sm, const LangOptions &lang,
CharSourceRange csr, CharSourceRange csr, FileID *fid) {
llvm::sys::fs::UniqueID *uniqueID) {
SourceLocation bloc = csr.getBegin(), eloc = csr.getEnd(); SourceLocation bloc = csr.getBegin(), eloc = csr.getEnd();
std::pair<FileID, unsigned> binfo = sm.getDecomposedLoc(bloc), std::pair<FileID, unsigned> binfo = sm.getDecomposedLoc(bloc),
einfo = sm.getDecomposedLoc(eloc); einfo = sm.getDecomposedLoc(eloc);
if (csr.isTokenRange()) if (csr.isTokenRange())
einfo.second += Lexer::MeasureTokenLength(eloc, sm, lang); einfo.second += Lexer::MeasureTokenLength(eloc, sm, lang);
if (uniqueID) { if (fid)
if (const FileEntry *F = sm.getFileEntryForID(binfo.first)) *fid = binfo.first;
*uniqueID = F->getUniqueID();
else
*uniqueID = llvm::sys::fs::UniqueID(0, 0);
}
return {decomposed2LineAndCol(sm, binfo), decomposed2LineAndCol(sm, einfo)}; return {decomposed2LineAndCol(sm, binfo), decomposed2LineAndCol(sm, einfo)};
} }
Range fromCharRange(const SourceManager &sm, const LangOptions &lang,
SourceRange sr, llvm::sys::fs::UniqueID *uniqueID) {
return fromCharSourceRange(sm, lang, CharSourceRange::getCharRange(sr),
uniqueID);
}
Range fromTokenRange(const SourceManager &sm, const LangOptions &lang, Range fromTokenRange(const SourceManager &sm, const LangOptions &lang,
SourceRange sr, llvm::sys::fs::UniqueID *uniqueID) { SourceRange sr, FileID *fid) {
return fromCharSourceRange(sm, lang, CharSourceRange::getTokenRange(sr), return fromCharSourceRange(sm, lang, CharSourceRange::getTokenRange(sr), fid);
uniqueID);
} }
Range fromTokenRangeDefaulted(const SourceManager &sm, const LangOptions &lang, Range fromTokenRangeDefaulted(const SourceManager &sm, const LangOptions &lang,
SourceRange sr, const FileEntry *fe, Range range) { SourceRange sr, FileID fid, Range range) {
auto decomposed = sm.getDecomposedLoc(sm.getExpansionLoc(sr.getBegin())); auto decomposed = sm.getDecomposedLoc(sm.getExpansionLoc(sr.getBegin()));
if (sm.getFileEntryForID(decomposed.first) == fe) if (decomposed.first == fid)
range.start = decomposed2LineAndCol(sm, decomposed); range.start = decomposed2LineAndCol(sm, decomposed);
SourceLocation sl = sm.getExpansionLoc(sr.getEnd()); SourceLocation sl = sm.getExpansionLoc(sr.getEnd());
decomposed = sm.getDecomposedLoc(sl); decomposed = sm.getDecomposedLoc(sl);
if (sm.getFileEntryForID(decomposed.first) == fe) { if (decomposed.first == fid) {
decomposed.second += Lexer::MeasureTokenLength(sl, sm, lang); decomposed.second += Lexer::MeasureTokenLength(sl, sm, lang);
range.end = decomposed2LineAndCol(sm, decomposed); range.end = decomposed2LineAndCol(sm, decomposed);
} }

View File

@ -22,20 +22,16 @@ std::string pathFromFileEntry(const clang::FileEntry &file);
Range fromCharSourceRange(const clang::SourceManager &sm, Range fromCharSourceRange(const clang::SourceManager &sm,
const clang::LangOptions &lang, const clang::LangOptions &lang,
clang::CharSourceRange sr, clang::CharSourceRange csr,
llvm::sys::fs::UniqueID *uniqueID = nullptr); clang::FileID *fid = nullptr);
Range fromCharRange(const clang::SourceManager &sm,
const clang::LangOptions &lang, clang::SourceRange sr,
llvm::sys::fs::UniqueID *uniqueID = nullptr);
Range fromTokenRange(const clang::SourceManager &sm, Range fromTokenRange(const clang::SourceManager &sm,
const clang::LangOptions &lang, clang::SourceRange sr, const clang::LangOptions &lang, clang::SourceRange sr,
llvm::sys::fs::UniqueID *uniqueID = nullptr); clang::FileID *fid = nullptr);
Range fromTokenRangeDefaulted(const clang::SourceManager &sm, Range fromTokenRangeDefaulted(const clang::SourceManager &sm,
const clang::LangOptions &lang, const clang::LangOptions &lang,
clang::SourceRange sr, const clang::FileEntry *fe, clang::SourceRange sr, clang::FileID fid,
Range range); Range range);
std::unique_ptr<clang::CompilerInvocation> std::unique_ptr<clang::CompilerInvocation>

View File

@ -39,8 +39,8 @@ struct File {
}; };
struct IndexParam { struct IndexParam {
std::unordered_map<llvm::sys::fs::UniqueID, File> uid2file; std::unordered_map<FileID, File> uid2file;
std::unordered_map<llvm::sys::fs::UniqueID, bool> uid2multi; std::unordered_map<FileID, bool> uid2multi;
struct DeclInfo { struct DeclInfo {
Usr usr; Usr usr;
std::string short_name; std::string short_name;
@ -53,14 +53,17 @@ struct IndexParam {
bool no_linkage; bool no_linkage;
IndexParam(VFS &vfs, bool no_linkage) : vfs(vfs), no_linkage(no_linkage) {} IndexParam(VFS &vfs, bool no_linkage) : vfs(vfs), no_linkage(no_linkage) {}
void seenFile(const FileEntry &file) { void seenFile(FileID fid) {
// 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] = uid2file.try_emplace(file.getUniqueID()); auto [it, inserted] = uid2file.try_emplace(fid);
if (inserted) { if (inserted) {
std::string path = pathFromFileEntry(file); const FileEntry *fe = ctx->getSourceManager().getFileEntryForID(fid);
if (!fe)
return;
std::string path = pathFromFileEntry(*fe);
it->second.path = path; it->second.path = path;
it->second.mtime = file.getModificationTime(); it->second.mtime = fe->getModificationTime();
if (!it->second.mtime) if (!it->second.mtime)
if (auto tim = lastWriteTime(path)) if (auto tim = lastWriteTime(path))
it->second.mtime = *tim; it->second.mtime = *tim;
@ -74,15 +77,16 @@ struct IndexParam {
} }
} }
IndexFile *consumeFile(const FileEntry &fe) { IndexFile *consumeFile(FileID fid) {
seenFile(fe); seenFile(fid);
return uid2file[fe.getUniqueID()].db.get(); return uid2file[fid].db.get();
} }
bool useMultiVersion(const FileEntry &fe) { bool useMultiVersion(FileID fid) {
auto it = uid2multi.try_emplace(fe.getUniqueID()); auto it = uid2multi.try_emplace(fid);
if (it.second) if (it.second)
it.first->second = multiVersionMatcher->matches(pathFromFileEntry(fe)); if (const FileEntry *fe = ctx->getSourceManager().getFileEntryForID(fid))
it.first->second = multiVersionMatcher->matches(pathFromFileEntry(*fe));
return it.first->second; return it.first->second;
} }
}; };
@ -608,27 +612,24 @@ public:
} }
} }
static int getFileLID(IndexFile *db, SourceManager &sm, const FileEntry &fe) { static int getFileLID(IndexFile *db, SourceManager &sm, FileID fid) {
auto [it, inserted] = db->uid2lid_and_path.try_emplace(fe.getUniqueID()); auto [it, inserted] = db->uid2lid_and_path.try_emplace(fid);
if (inserted) { if (inserted) {
it->second.first = db->uid2lid_and_path.size() - 1; const FileEntry *fe = sm.getFileEntryForID(fid);
SmallString<256> path = fe.tryGetRealPathName(); if (!fe) {
if (path.empty()) it->second.first = -1;
path = fe.getName();
if (!llvm::sys::path::is_absolute(path) &&
!sm.getFileManager().makeAbsolutePath(path))
return -1; return -1;
it->second.second = llvm::sys::path::convert_to_slash(path.str()); }
it->second.first = db->uid2lid_and_path.size() - 1;
it->second.second = pathFromFileEntry(*fe);
} }
return it->second.first; return it->second.first;
} }
void addMacroUse(IndexFile *db, SourceManager &sm, Usr usr, Kind kind, void addMacroUse(IndexFile *db, SourceManager &sm, Usr usr, Kind kind,
SourceLocation sl) const { SourceLocation sl) const {
const FileEntry *FE = sm.getFileEntryForID(sm.getFileID(sl)); FileID fid = sm.getFileID(sl);
if (!FE) int lid = getFileLID(db, sm, fid);
return;
int lid = getFileLID(db, sm, *FE);
if (lid < 0) if (lid < 0)
return; return;
Range spell = fromTokenRange(sm, ctx->getLangOpts(), SourceRange(sl, sl)); Range spell = fromTokenRange(sm, ctx->getLangOpts(), SourceRange(sl, sl));
@ -689,27 +690,25 @@ public:
const LangOptions &lang = ctx->getLangOpts(); const LangOptions &lang = ctx->getLangOpts();
FileID fid; FileID fid;
SourceLocation spell = sm.getSpellingLoc(src_loc); SourceLocation spell = sm.getSpellingLoc(src_loc);
const FileEntry *fe;
Range loc; Range loc;
auto r = sm.isMacroArgExpansion(src_loc) auto r = sm.isMacroArgExpansion(src_loc)
? CharSourceRange::getTokenRange(spell) ? CharSourceRange::getTokenRange(spell)
: sm.getExpansionRange(src_loc); : sm.getExpansionRange(src_loc);
loc = fromCharSourceRange(sm, lang, r); loc = fromCharSourceRange(sm, lang, r);
fid = sm.getFileID(r.getBegin()); fid = sm.getFileID(r.getBegin());
fe = sm.getFileEntryForID(fid); if (fid.isInvalid())
if (!fe)
return true; return true;
int lid = -1; int lid = -1;
IndexFile *db; IndexFile *db;
if (g_config->index.multiVersion && param.useMultiVersion(*fe)) { if (g_config->index.multiVersion && param.useMultiVersion(fid)) {
db = param.consumeFile(*sm.getFileEntryForID(sm.getMainFileID())); db = param.consumeFile(sm.getMainFileID());
if (!db) if (!db)
return true; return true;
param.seenFile(*fe); param.seenFile(fid);
if (!sm.isWrittenInMainFile(r.getBegin())) if (!sm.isWrittenInMainFile(r.getBegin()))
lid = getFileLID(db, sm, *fe); lid = getFileLID(db, sm, fid);
} else { } else {
db = param.consumeFile(*fe); db = param.consumeFile(fid);
if (!db) if (!db)
return true; return true;
} }
@ -771,13 +770,13 @@ public:
if (is_def) { if (is_def) {
SourceRange sr = origD->getSourceRange(); SourceRange sr = origD->getSourceRange();
entity->def.spell = {use, entity->def.spell = {use,
fromTokenRangeDefaulted(sm, lang, sr, fe, loc)}; fromTokenRangeDefaulted(sm, lang, sr, fid, loc)};
entity->def.parent_kind = SymbolKind::File; entity->def.parent_kind = SymbolKind::File;
getKind(cast<Decl>(sem_dc), entity->def.parent_kind); getKind(cast<Decl>(sem_dc), entity->def.parent_kind);
} else if (is_decl) { } else if (is_decl) {
SourceRange sr = origD->getSourceRange(); SourceRange sr = origD->getSourceRange();
entity->declarations.push_back( entity->declarations.push_back(
{use, fromTokenRangeDefaulted(sm, lang, sr, fe, loc)}); {use, fromTokenRangeDefaulted(sm, lang, sr, fid, loc)});
} else { } else {
entity->uses.push_back(use); entity->uses.push_back(use);
return; return;
@ -1073,6 +1072,11 @@ class IndexPPCallbacks : public PPCallbacks {
public: public:
IndexPPCallbacks(SourceManager &sm, IndexParam &param) IndexPPCallbacks(SourceManager &sm, IndexParam &param)
: sm(sm), param(param) {} : sm(sm), param(param) {}
void FileChanged(SourceLocation sl, FileChangeReason reason,
SrcMgr::CharacteristicKind, FileID) override {
if (reason == FileChangeReason::EnterFile)
(void)param.consumeFile(sm.getFileID(sl));
}
void InclusionDirective(SourceLocation hashLoc, const Token &tok, void InclusionDirective(SourceLocation hashLoc, const Token &tok,
StringRef included, bool isAngled, StringRef included, bool isAngled,
CharSourceRange filenameRange, const FileEntry *file, CharSourceRange filenameRange, const FileEntry *file,
@ -1083,11 +1087,8 @@ public:
return; return;
auto spell = fromCharSourceRange(sm, param.ctx->getLangOpts(), auto spell = fromCharSourceRange(sm, param.ctx->getLangOpts(),
filenameRange, nullptr); filenameRange, nullptr);
const FileEntry *fe = FileID fid = sm.getFileID(filenameRange.getBegin());
sm.getFileEntryForID(sm.getFileID(filenameRange.getBegin())); if (IndexFile *db = param.consumeFile(fid)) {
if (!fe)
return;
if (IndexFile *db = param.consumeFile(*fe)) {
std::string path = pathFromFileEntry(*file); std::string path = pathFromFileEntry(*file);
if (path.size()) if (path.size())
db->includes.push_back({spell.start.line, intern(path)}); db->includes.push_back({spell.start.line, intern(path)});
@ -1096,10 +1097,8 @@ public:
void MacroDefined(const Token &tok, const MacroDirective *md) override { void MacroDefined(const Token &tok, const MacroDirective *md) override {
const LangOptions &lang = param.ctx->getLangOpts(); const LangOptions &lang = param.ctx->getLangOpts();
SourceLocation sl = md->getLocation(); SourceLocation sl = md->getLocation();
const FileEntry *fe = sm.getFileEntryForID(sm.getFileID(sl)); FileID fid = sm.getFileID(sl);
if (!fe) if (IndexFile *db = param.consumeFile(fid)) {
return;
if (IndexFile *db = param.consumeFile(*fe)) {
auto [name, usr] = getMacro(tok); auto [name, usr] = getMacro(tok);
IndexVar &var = db->toVar(usr); IndexVar &var = db->toVar(usr);
Range range = fromTokenRange(sm, lang, {sl, sl}, nullptr); Range range = fromTokenRange(sm, lang, {sl, sl}, nullptr);
@ -1124,15 +1123,12 @@ public:
} }
void MacroExpands(const Token &tok, const MacroDefinition &, SourceRange sr, void MacroExpands(const Token &tok, const MacroDefinition &, SourceRange sr,
const MacroArgs *) override { const MacroArgs *) override {
llvm::sys::fs::UniqueID uniqueID;
SourceLocation sl = sm.getSpellingLoc(sr.getBegin()); SourceLocation sl = sm.getSpellingLoc(sr.getBegin());
const FileEntry *fe = sm.getFileEntryForID(sm.getFileID(sl)); FileID fid = sm.getFileID(sl);
if (!fe) if (IndexFile *db = param.consumeFile(fid)) {
return;
if (IndexFile *db = param.consumeFile(*fe)) {
IndexVar &var = db->toVar(getMacro(tok).second); IndexVar &var = db->toVar(getMacro(tok).second);
var.uses.push_back( var.uses.push_back(
{{fromTokenRange(sm, param.ctx->getLangOpts(), {sl, sl}, &uniqueID), {{fromTokenRange(sm, param.ctx->getLangOpts(), {sl, sl}, nullptr),
Role::Dynamic}}); Role::Dynamic}});
} }
} }
@ -1146,8 +1142,9 @@ public:
void SourceRangeSkipped(SourceRange sr, SourceLocation) override { void SourceRangeSkipped(SourceRange sr, SourceLocation) override {
Range range = fromCharSourceRange(sm, param.ctx->getLangOpts(), Range range = fromCharSourceRange(sm, param.ctx->getLangOpts(),
CharSourceRange::getCharRange(sr)); CharSourceRange::getCharRange(sr));
if (const FileEntry *fe = sm.getFileEntryForID(sm.getFileID(sr.getBegin()))) FileID fid = sm.getFileID(sr.getBegin());
if (IndexFile *db = param.consumeFile(*fe)) if (fid.isValid())
if (IndexFile *db = param.consumeFile(fid))
db->skipped_ranges.push_back(range); db->skipped_ranges.push_back(range);
} }
}; };
@ -1317,7 +1314,8 @@ index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
entry->import_file = main; entry->import_file = main;
entry->args = args; entry->args = args;
for (auto &[_, it] : entry->uid2lid_and_path) for (auto &[_, it] : entry->uid2lid_and_path)
entry->lid2path.emplace_back(it.first, std::move(it.second)); if (it.first >= 0)
entry->lid2path.emplace_back(it.first, std::move(it.second));
entry->uid2lid_and_path.clear(); entry->uid2lid_and_path.clear();
for (auto &it : entry->usr2func) { for (auto &it : entry->usr2func) {
// e.g. declaration + out-of-line definition // e.g. declaration + out-of-line definition
@ -1337,6 +1335,8 @@ index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
// Update dependencies for the file. // Update dependencies for the file.
for (auto &[_, file] : param.uid2file) { for (auto &[_, file] : param.uid2file) {
const std::string &path = file.path; const std::string &path = file.path;
if (path.empty())
continue;
if (path == entry->path) if (path == entry->path)
entry->mtime = file.mtime; entry->mtime = file.mtime;
else if (path != entry->import_file) else if (path != entry->import_file)

View File

@ -8,7 +8,7 @@
#include "serializer.hh" #include "serializer.hh"
#include "utils.hh" #include "utils.hh"
#include <clang/Basic/FileManager.h> #include <clang/Basic/SourceLocation.h>
#include <clang/Basic/Specifiers.h> #include <clang/Basic/Specifiers.h>
#include <llvm/ADT/CachedHashString.h> #include <llvm/ADT/CachedHashString.h>
#include <llvm/ADT/DenseMap.h> #include <llvm/ADT/DenseMap.h>
@ -19,12 +19,8 @@
#include <vector> #include <vector>
namespace std { namespace std {
template <> struct hash<llvm::sys::fs::UniqueID> { template <> struct hash<clang::FileID> {
std::size_t operator()(llvm::sys::fs::UniqueID ID) const { std::size_t operator()(clang::FileID fid) const { return fid.getHashValue(); }
size_t ret = ID.getDevice();
ccls::hash_combine(ret, ID.getFile());
return ret;
}
}; };
} // namespace std } // namespace std
@ -294,7 +290,7 @@ struct IndexFile {
bool no_linkage; bool no_linkage;
// 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<clang::FileID, std::pair<int, std::string>>
uid2lid_and_path; uid2lid_and_path;
std::vector<std::pair<int, std::string>> lid2path; std::vector<std::pair<int, std::string>> lid2path;