mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-24 08:35:08 +00:00
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:
parent
b804a04380
commit
edc73ceb10
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
106
src/indexer.cc
106
src/indexer.cc
@ -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 ¶m)
|
||||
: 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)
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user