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 b804a04380
commit edc73ceb10
4 changed files with 69 additions and 89 deletions

View File

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

View File

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

View File

@ -51,8 +51,8 @@ struct File {
};
struct IndexParam {
std::unordered_map<llvm::sys::fs::UniqueID, File> uid2file;
std::unordered_map<llvm::sys::fs::UniqueID, bool> uid2multi;
std::unordered_map<FileID, File> uid2file;
std::unordered_map<FileID, bool> uid2multi;
struct DeclInfo {
Usr usr;
std::string short_name;
@ -65,14 +65,17 @@ struct IndexParam {
bool 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
// generating an index for it):
auto [it, inserted] = uid2file.try_emplace(file.getUniqueID());
auto [it, inserted] = uid2file.try_emplace(fid);
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.mtime = file.getModificationTime();
it->second.mtime = fe->getModificationTime();
if (!it->second.mtime)
if (auto tim = lastWriteTime(path))
it->second.mtime = *tim;
@ -86,15 +89,16 @@ struct IndexParam {
}
}
IndexFile *consumeFile(const FileEntry &fe) {
seenFile(fe);
return uid2file[fe.getUniqueID()].db.get();
IndexFile *consumeFile(FileID fid) {
seenFile(fid);
return uid2file[fid].db.get();
}
bool useMultiVersion(const FileEntry &fe) {
auto it = uid2multi.try_emplace(fe.getUniqueID());
bool useMultiVersion(FileID fid) {
auto it = uid2multi.try_emplace(fid);
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;
}
};
@ -622,27 +626,24 @@ public:
}
}
static int getFileLID(IndexFile *db, SourceManager &sm, const FileEntry &fe) {
auto [it, inserted] = db->uid2lid_and_path.try_emplace(fe.getUniqueID());
static int getFileLID(IndexFile *db, SourceManager &sm, FileID fid) {
auto [it, inserted] = db->uid2lid_and_path.try_emplace(fid);
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))
const FileEntry *fe = sm.getFileEntryForID(fid);
if (!fe) {
it->second.first = -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;
}
void addMacroUse(IndexFile *db, SourceManager &sm, Usr usr, Kind kind,
SourceLocation sl) const {
const FileEntry *FE = sm.getFileEntryForID(sm.getFileID(sl));
if (!FE)
return;
int lid = getFileLID(db, sm, *FE);
FileID fid = sm.getFileID(sl);
int lid = getFileLID(db, sm, fid);
if (lid < 0)
return;
Range spell = fromTokenRange(sm, ctx->getLangOpts(), SourceRange(sl, sl));
@ -703,27 +704,25 @@ public:
const LangOptions &lang = ctx->getLangOpts();
FileID fid;
SourceLocation spell = sm.getSpellingLoc(src_loc);
const FileEntry *fe;
Range loc;
auto r = sm.isMacroArgExpansion(src_loc)
? CharSourceRange::getTokenRange(spell)
: sm.getExpansionRange(src_loc);
loc = fromCharSourceRange(sm, lang, r);
fid = sm.getFileID(r.getBegin());
fe = sm.getFileEntryForID(fid);
if (!fe)
if (fid.isInvalid())
return true;
int lid = -1;
IndexFile *db;
if (g_config->index.multiVersion && param.useMultiVersion(*fe)) {
db = param.consumeFile(*sm.getFileEntryForID(sm.getMainFileID()));
if (g_config->index.multiVersion && param.useMultiVersion(fid)) {
db = param.consumeFile(sm.getMainFileID());
if (!db)
return true;
param.seenFile(*fe);
param.seenFile(fid);
if (!sm.isWrittenInMainFile(r.getBegin()))
lid = getFileLID(db, sm, *fe);
lid = getFileLID(db, sm, fid);
} else {
db = param.consumeFile(*fe);
db = param.consumeFile(fid);
if (!db)
return true;
}
@ -785,12 +784,12 @@ public:
if (is_def) {
SourceRange sr = origD->getSourceRange();
entity->def.spell = {use,
fromTokenRangeDefaulted(sm, lang, sr, fe, loc)};
fromTokenRangeDefaulted(sm, lang, sr, fid, loc)};
getKind(cast<Decl>(sem_dc), entity->def.parent_kind);
} else if (is_decl) {
SourceRange sr = origD->getSourceRange();
entity->declarations.push_back(
{use, fromTokenRangeDefaulted(sm, lang, sr, fe, loc)});
{use, fromTokenRangeDefaulted(sm, lang, sr, fid, loc)});
} else {
entity->uses.push_back(use);
return;
@ -1086,6 +1085,11 @@ class IndexPPCallbacks : public PPCallbacks {
public:
IndexPPCallbacks(SourceManager &sm, IndexParam &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,
StringRef included, bool isAngled,
CharSourceRange filenameRange, const FileEntry *file,
@ -1096,11 +1100,8 @@ public:
return;
auto spell = fromCharSourceRange(sm, param.ctx->getLangOpts(),
filenameRange, nullptr);
const FileEntry *fe =
sm.getFileEntryForID(sm.getFileID(filenameRange.getBegin()));
if (!fe)
return;
if (IndexFile *db = param.consumeFile(*fe)) {
FileID fid = sm.getFileID(filenameRange.getBegin());
if (IndexFile *db = param.consumeFile(fid)) {
std::string path = pathFromFileEntry(*file);
if (path.size())
db->includes.push_back({spell.start.line, intern(path)});
@ -1109,10 +1110,8 @@ public:
void MacroDefined(const Token &tok, const MacroDirective *md) override {
const LangOptions &lang = param.ctx->getLangOpts();
SourceLocation sl = md->getLocation();
const FileEntry *fe = sm.getFileEntryForID(sm.getFileID(sl));
if (!fe)
return;
if (IndexFile *db = param.consumeFile(*fe)) {
FileID fid = sm.getFileID(sl);
if (IndexFile *db = param.consumeFile(fid)) {
auto [name, usr] = getMacro(tok);
IndexVar &var = db->toVar(usr);
Range range = fromTokenRange(sm, lang, {sl, sl}, nullptr);
@ -1137,15 +1136,12 @@ public:
}
void MacroExpands(const Token &tok, const MacroDefinition &, SourceRange sr,
const MacroArgs *) override {
llvm::sys::fs::UniqueID uniqueID;
SourceLocation sl = sm.getSpellingLoc(sr.getBegin());
const FileEntry *fe = sm.getFileEntryForID(sm.getFileID(sl));
if (!fe)
return;
if (IndexFile *db = param.consumeFile(*fe)) {
FileID fid = sm.getFileID(sl);
if (IndexFile *db = param.consumeFile(fid)) {
IndexVar &var = db->toVar(getMacro(tok).second);
var.uses.push_back(
{{fromTokenRange(sm, param.ctx->getLangOpts(), {sl, sl}, &uniqueID),
{{fromTokenRange(sm, param.ctx->getLangOpts(), {sl, sl}, nullptr),
Role::Dynamic}});
}
}
@ -1159,8 +1155,9 @@ public:
void SourceRangeSkipped(SourceRange sr, SourceLocation) override {
Range range = fromCharSourceRange(sm, param.ctx->getLangOpts(),
CharSourceRange::getCharRange(sr));
if (const FileEntry *fe = sm.getFileEntryForID(sm.getFileID(sr.getBegin())))
if (IndexFile *db = param.consumeFile(*fe))
FileID fid = sm.getFileID(sr.getBegin());
if (fid.isValid())
if (IndexFile *db = param.consumeFile(fid))
db->skipped_ranges.push_back(range);
}
};
@ -1330,7 +1327,8 @@ index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
entry->import_file = main;
entry->args = args;
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();
for (auto &it : entry->usr2func) {
// e.g. declaration + out-of-line definition
@ -1350,6 +1348,8 @@ index(SemaManager *manager, WorkingFiles *wfiles, VFS *vfs,
// Update dependencies for the file.
for (auto &[_, file] : param.uid2file) {
const std::string &path = file.path;
if (path.empty())
continue;
if (path == entry->path)
entry->mtime = file.mtime;
else if (path != entry->import_file)

View File

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