mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 09:05:10 +00:00
Support uses from other files and improve references in macro replacement-list
This commit is contained in:
parent
24e99fd767
commit
b759798e5d
@ -23,14 +23,14 @@ OUTPUT:
|
|||||||
"short_name": "a",
|
"short_name": "a",
|
||||||
"kind": 12,
|
"kind": 12,
|
||||||
"storage": 0,
|
"storage": 0,
|
||||||
"declarations": ["12:1-12:4|0|1|1"],
|
"declarations": ["12:1-12:20|0|1|1"],
|
||||||
"spell": "12:1-12:4|0|1|2",
|
"spell": "12:1-12:20|0|1|2",
|
||||||
"extent": "1:1-1:1|0|1|0",
|
"extent": "1:1-1:1|0|1|0",
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"bases": [],
|
"bases": [],
|
||||||
"derived": [],
|
"derived": [],
|
||||||
"vars": [],
|
"vars": [],
|
||||||
"uses": ["2:7-2:8|0|1|64", "3:7-3:8|0|1|64"],
|
"uses": ["2:7-2:8|0|1|64|0", "3:7-3:8|0|1|64|0"],
|
||||||
"callees": []
|
"callees": []
|
||||||
}, {
|
}, {
|
||||||
"usr": 14400399977994209582,
|
"usr": 14400399977994209582,
|
||||||
@ -46,7 +46,7 @@ OUTPUT:
|
|||||||
"bases": [],
|
"bases": [],
|
||||||
"derived": [],
|
"derived": [],
|
||||||
"vars": [],
|
"vars": [],
|
||||||
"uses": ["12:5-12:10|0|1|16420"],
|
"uses": ["12:1-12:20|0|1|16420", "12:5-12:10|0|1|64|0"],
|
||||||
"callees": []
|
"callees": []
|
||||||
}],
|
}],
|
||||||
"usr2type": [{
|
"usr2type": [{
|
||||||
@ -75,7 +75,7 @@ OUTPUT:
|
|||||||
"spell": "9:11-9:16|0|1|2",
|
"spell": "9:11-9:16|0|1|2",
|
||||||
"extent": "9:1-9:20|0|1|0",
|
"extent": "9:1-9:20|0|1|0",
|
||||||
"type": 53,
|
"type": 53,
|
||||||
"uses": ["12:14-12:19|0|1|12"],
|
"uses": ["12:1-12:20|0|1|12", "12:14-12:19|0|1|64|0"],
|
||||||
"kind": 13,
|
"kind": 13,
|
||||||
"storage": 0
|
"storage": 0
|
||||||
}, {
|
}, {
|
||||||
@ -88,7 +88,7 @@ OUTPUT:
|
|||||||
"spell": "1:9-1:12|0|1|2",
|
"spell": "1:9-1:12|0|1|2",
|
||||||
"extent": "1:9-3:32|0|1|0",
|
"extent": "1:9-3:32|0|1|0",
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"uses": ["12:1-12:20|0|1|4"],
|
"uses": ["12:1-12:4|0|1|64"],
|
||||||
"kind": 255,
|
"kind": 255,
|
||||||
"storage": 0
|
"storage": 0
|
||||||
}]
|
}]
|
||||||
|
@ -20,13 +20,13 @@ OUTPUT:
|
|||||||
"kind": 9,
|
"kind": 9,
|
||||||
"storage": 0,
|
"storage": 0,
|
||||||
"declarations": [],
|
"declarations": [],
|
||||||
"spell": "5:12-5:15|15041163540773201510|2|1026",
|
"spell": "5:3-5:16|15041163540773201510|2|1026",
|
||||||
"extent": "1:1-1:1|15041163540773201510|2|0",
|
"extent": "1:1-1:1|15041163540773201510|2|0",
|
||||||
"declaring_type": 0,
|
"declaring_type": 0,
|
||||||
"bases": [],
|
"bases": [],
|
||||||
"derived": [],
|
"derived": [],
|
||||||
"vars": [],
|
"vars": [],
|
||||||
"uses": [],
|
"uses": ["5:12-5:15|0|1|64|0"],
|
||||||
"callees": []
|
"callees": []
|
||||||
}],
|
}],
|
||||||
"usr2type": [{
|
"usr2type": [{
|
||||||
@ -60,7 +60,7 @@ OUTPUT:
|
|||||||
"funcs": [13788753348312146871],
|
"funcs": [13788753348312146871],
|
||||||
"vars": [],
|
"vars": [],
|
||||||
"instances": [],
|
"instances": [],
|
||||||
"uses": ["5:12-5:15|0|1|4"]
|
"uses": ["5:3-5:16|0|1|4", "5:12-5:15|0|1|64|0"]
|
||||||
}],
|
}],
|
||||||
"usr2var": [{
|
"usr2var": [{
|
||||||
"usr": 1569772797058982873,
|
"usr": 1569772797058982873,
|
||||||
@ -72,7 +72,7 @@ OUTPUT:
|
|||||||
"spell": "1:9-1:10|0|1|2",
|
"spell": "1:9-1:10|0|1|2",
|
||||||
"extent": "1:9-1:12|0|1|0",
|
"extent": "1:9-1:12|0|1|0",
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"uses": ["8:9-8:10|0|1|4"],
|
"uses": ["8:9-8:10|0|1|64"],
|
||||||
"kind": 255,
|
"kind": 255,
|
||||||
"storage": 0
|
"storage": 0
|
||||||
}, {
|
}, {
|
||||||
@ -85,7 +85,7 @@ OUTPUT:
|
|||||||
"spell": "2:9-2:17|0|1|2",
|
"spell": "2:9-2:17|0|1|2",
|
||||||
"extent": "2:9-2:46|0|1|0",
|
"extent": "2:9-2:46|0|1|0",
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"uses": ["5:3-5:16|0|1|4"],
|
"uses": ["5:3-5:11|0|1|64"],
|
||||||
"kind": 255,
|
"kind": 255,
|
||||||
"storage": 0
|
"storage": 0
|
||||||
}, {
|
}, {
|
||||||
|
@ -33,7 +33,7 @@ OUTPUT: funky_enum.h
|
|||||||
"qual_name_offset": 0,
|
"qual_name_offset": 0,
|
||||||
"short_name": "A",
|
"short_name": "A",
|
||||||
"hover": "A = 0",
|
"hover": "A = 0",
|
||||||
"comments": "This file cannot be built directory. It is included in an enum definition of\r\nanother file.",
|
"comments": "This file cannot be built directory. It is included in an enum definition of\nanother file.",
|
||||||
"declarations": [],
|
"declarations": [],
|
||||||
"spell": "4:1-4:2|16985894625255407295|2|1026",
|
"spell": "4:1-4:2|16985894625255407295|2|1026",
|
||||||
"extent": "4:1-4:2|16985894625255407295|2|0",
|
"extent": "4:1-4:2|16985894625255407295|2|0",
|
||||||
@ -47,7 +47,7 @@ OUTPUT: funky_enum.h
|
|||||||
"qual_name_offset": 0,
|
"qual_name_offset": 0,
|
||||||
"short_name": "C",
|
"short_name": "C",
|
||||||
"hover": "C = 2",
|
"hover": "C = 2",
|
||||||
"comments": "This file cannot be built directory. It is included in an enum definition of\r\nanother file.",
|
"comments": "This file cannot be built directory. It is included in an enum definition of\nanother file.",
|
||||||
"declarations": [],
|
"declarations": [],
|
||||||
"spell": "6:1-6:2|16985894625255407295|2|1026",
|
"spell": "6:1-6:2|16985894625255407295|2|1026",
|
||||||
"extent": "6:1-6:2|16985894625255407295|2|0",
|
"extent": "6:1-6:2|16985894625255407295|2|0",
|
||||||
@ -61,7 +61,7 @@ OUTPUT: funky_enum.h
|
|||||||
"qual_name_offset": 0,
|
"qual_name_offset": 0,
|
||||||
"short_name": "B",
|
"short_name": "B",
|
||||||
"hover": "B = 1",
|
"hover": "B = 1",
|
||||||
"comments": "This file cannot be built directory. It is included in an enum definition of\r\nanother file.",
|
"comments": "This file cannot be built directory. It is included in an enum definition of\nanother file.",
|
||||||
"declarations": [],
|
"declarations": [],
|
||||||
"spell": "5:1-5:2|16985894625255407295|2|1026",
|
"spell": "5:1-5:2|16985894625255407295|2|1026",
|
||||||
"extent": "5:1-5:2|16985894625255407295|2|0",
|
"extent": "5:1-5:2|16985894625255407295|2|0",
|
||||||
|
@ -23,7 +23,7 @@ OUTPUT:
|
|||||||
"bases": [],
|
"bases": [],
|
||||||
"derived": [],
|
"derived": [],
|
||||||
"vars": [],
|
"vars": [],
|
||||||
"uses": ["6:14-6:20|0|1|16420"],
|
"uses": ["6:3-6:33|0|1|16420", "6:14-6:20|0|1|64|0"],
|
||||||
"callees": []
|
"callees": []
|
||||||
}, {
|
}, {
|
||||||
"usr": 11404881820527069090,
|
"usr": 11404881820527069090,
|
||||||
@ -53,7 +53,7 @@ OUTPUT:
|
|||||||
"spell": "1:9-1:19|0|1|2",
|
"spell": "1:9-1:19|0|1|2",
|
||||||
"extent": "1:9-1:24|0|1|0",
|
"extent": "1:9-1:24|0|1|0",
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"uses": ["6:3-6:33|0|1|4"],
|
"uses": ["6:3-6:13|0|1|64"],
|
||||||
"kind": 255,
|
"kind": 255,
|
||||||
"storage": 0
|
"storage": 0
|
||||||
}]
|
}]
|
||||||
|
149
src/indexer.cc
149
src/indexer.cc
@ -15,6 +15,7 @@ using ccls::Intern;
|
|||||||
#include <clang/Lex/PreprocessorOptions.h>
|
#include <clang/Lex/PreprocessorOptions.h>
|
||||||
#include <llvm/ADT/DenseSet.h>
|
#include <llvm/ADT/DenseSet.h>
|
||||||
#include <llvm/Support/CrashRecoveryContext.h>
|
#include <llvm/Support/CrashRecoveryContext.h>
|
||||||
|
#include <llvm/Support/Path.h>
|
||||||
#include <llvm/Support/Timer.h>
|
#include <llvm/Support/Timer.h>
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
using llvm::Timer;
|
using llvm::Timer;
|
||||||
@ -47,8 +48,7 @@ struct IndexParam {
|
|||||||
: Unit(Unit), file_consumer(file_consumer) {}
|
: Unit(Unit), file_consumer(file_consumer) {}
|
||||||
|
|
||||||
IndexFile *ConsumeFile(const FileEntry &File) {
|
IndexFile *ConsumeFile(const FileEntry &File) {
|
||||||
IndexFile *db =
|
IndexFile *db = file_consumer->TryConsumeFile(File, &file_contents);
|
||||||
file_consumer->TryConsumeFile(File, &file_contents);
|
|
||||||
|
|
||||||
// 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):
|
||||||
@ -530,15 +530,25 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddMacroUse(SourceManager &SM, Usr usr, SymbolKind kind,
|
void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
|
||||||
SourceLocation Spell) const {
|
SourceLocation Spell) const {
|
||||||
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
|
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
|
||||||
if (!FE) return;
|
if (!FE) return;
|
||||||
IndexFile *db = param.ConsumeFile(*FE);
|
auto UID = FE->getUniqueID();
|
||||||
if (!db) return;
|
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();
|
||||||
|
}
|
||||||
Range spell =
|
Range spell =
|
||||||
FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, Spell));
|
FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, Spell));
|
||||||
Use use = GetUse(db, spell, nullptr, Role::Dynamic);
|
Use use{{spell, 0, SymbolKind::File, Role::Dynamic}, it->second.first};
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolKind::Func:
|
case SymbolKind::Func:
|
||||||
db->ToFunc(usr).uses.push_back(use);
|
db->ToFunc(usr).uses.push_back(use);
|
||||||
@ -582,26 +592,21 @@ public:
|
|||||||
FileID LocFID;
|
FileID LocFID;
|
||||||
#endif
|
#endif
|
||||||
SourceLocation Spell = SM.getSpellingLoc(Loc);
|
SourceLocation Spell = SM.getSpellingLoc(Loc);
|
||||||
Loc = SM.getFileLoc(Loc);
|
const FileEntry *FE;
|
||||||
Range loc = FromTokenRange(SM, Lang, SourceRange(Loc, Loc));
|
Range loc;
|
||||||
LocFID = SM.getFileID(Loc);
|
|
||||||
const FileEntry *FE = SM.getFileEntryForID(LocFID);
|
|
||||||
if (!FE) {
|
|
||||||
// TODO
|
|
||||||
#if LLVM_VERSION_MAJOR < 7
|
#if LLVM_VERSION_MAJOR < 7
|
||||||
auto P = SM.getExpansionRange(Loc);
|
auto P = SM.getExpansionRange(Loc);
|
||||||
loc = FromCharRange(SM, Ctx->getLangOpts(), SourceRange(P.first, P.second));
|
loc = FromCharRange(SM, Ctx->getLangOpts(), SourceRange(P.first, P.second));
|
||||||
LocFID = SM.getFileID(P.first);
|
LocFID = SM.getFileID(P.first);
|
||||||
FE = SM.getFileEntryForID(LocFID);
|
FE = SM.getFileEntryForID(LocFID);
|
||||||
#else
|
#else
|
||||||
auto R = SM.getExpansionRange(Loc);
|
auto R = SM.getExpansionRange(Loc);
|
||||||
loc = FromTokenRange(SM, Lang, R.getAsRange());
|
loc = FromTokenRange(SM, Lang, R.getAsRange());
|
||||||
LocFID = SM.getFileID(R.getBegin());
|
LocFID = SM.getFileID(R.getBegin());
|
||||||
FE = SM.getFileEntryForID(LocFID);
|
FE = SM.getFileEntryForID(LocFID);
|
||||||
#endif
|
#endif
|
||||||
if (!FE)
|
if (!FE)
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
IndexFile *db = param.ConsumeFile(*FE);
|
IndexFile *db = param.ConsumeFile(*FE);
|
||||||
if (!db)
|
if (!db)
|
||||||
return true;
|
return true;
|
||||||
@ -647,7 +652,7 @@ public:
|
|||||||
func = &db->ToFunc(usr);
|
func = &db->ToFunc(usr);
|
||||||
do_def_decl(func);
|
do_def_decl(func);
|
||||||
if (Spell != Loc)
|
if (Spell != Loc)
|
||||||
AddMacroUse(SM, usr, SymbolKind::Func, Spell);
|
AddMacroUse(db, SM, usr, SymbolKind::Func, Spell);
|
||||||
if (func->def.detailed_name[0] == '\0')
|
if (func->def.detailed_name[0] == '\0')
|
||||||
SetName(OrigD, info->short_name, info->qualified, func->def);
|
SetName(OrigD, info->short_name, info->qualified, func->def);
|
||||||
if (is_def || is_decl) {
|
if (is_def || is_decl) {
|
||||||
@ -660,7 +665,7 @@ public:
|
|||||||
type = &db->ToType(usr);
|
type = &db->ToType(usr);
|
||||||
do_def_decl(type);
|
do_def_decl(type);
|
||||||
if (Spell != Loc)
|
if (Spell != Loc)
|
||||||
AddMacroUse(SM, usr, SymbolKind::Type, Spell);
|
AddMacroUse(db, SM, usr, SymbolKind::Type, Spell);
|
||||||
if (type->def.detailed_name[0] == '\0')
|
if (type->def.detailed_name[0] == '\0')
|
||||||
SetName(OrigD, info->short_name, info->qualified, type->def);
|
SetName(OrigD, info->short_name, info->qualified, type->def);
|
||||||
if (is_def || is_decl) {
|
if (is_def || is_decl) {
|
||||||
@ -673,7 +678,7 @@ public:
|
|||||||
var = &db->ToVar(usr);
|
var = &db->ToVar(usr);
|
||||||
do_def_decl(var);
|
do_def_decl(var);
|
||||||
if (Spell != Loc)
|
if (Spell != Loc)
|
||||||
AddMacroUse(SM, usr, SymbolKind::Var, Spell);
|
AddMacroUse(db, SM, usr, SymbolKind::Var, Spell);
|
||||||
if (var->def.detailed_name[0] == '\0')
|
if (var->def.detailed_name[0] == '\0')
|
||||||
SetVarName(OrigD, info->short_name, info->qualified, var->def);
|
SetVarName(OrigD, info->short_name, info->qualified, var->def);
|
||||||
QualType T;
|
QualType T;
|
||||||
@ -994,14 +999,16 @@ public:
|
|||||||
void MacroExpands(const Token &Tok, const MacroDefinition &MD,
|
void MacroExpands(const Token &Tok, const MacroDefinition &MD,
|
||||||
SourceRange R, const MacroArgs *Args) override {
|
SourceRange R, const MacroArgs *Args) override {
|
||||||
llvm::sys::fs::UniqueID UniqueID;
|
llvm::sys::fs::UniqueID UniqueID;
|
||||||
auto range = FromTokenRange(SM, param.Ctx->getLangOpts(), R, &UniqueID);
|
SourceLocation L = SM.getSpellingLoc(R.getBegin());
|
||||||
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(R.getBegin()));
|
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
|
||||||
if (!FE)
|
if (!FE)
|
||||||
return;
|
return;
|
||||||
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
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);
|
||||||
var.uses.push_back({{range, 0, SymbolKind::File, Role::Reference}});
|
var.uses.push_back(
|
||||||
|
{{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
|
||||||
|
SymbolKind::File, Role::Dynamic}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MacroUndefined(const Token &Tok, const MacroDefinition &MD,
|
void MacroUndefined(const Token &Tok, const MacroDefinition &MD,
|
||||||
@ -1033,8 +1040,8 @@ public:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const int IndexFile::kMajorVersion = 16;
|
const int IndexFile::kMajorVersion = 17;
|
||||||
const int IndexFile::kMinorVersion = 1;
|
const int IndexFile::kMinorVersion = 0;
|
||||||
|
|
||||||
IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
|
IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
|
||||||
const std::string &contents)
|
const std::string &contents)
|
||||||
@ -1185,6 +1192,9 @@ std::vector<std::unique_ptr<IndexFile>> Index(
|
|||||||
for (std::unique_ptr<IndexFile>& entry : result) {
|
for (std::unique_ptr<IndexFile>& entry : result) {
|
||||||
entry->import_file = file;
|
entry->import_file = file;
|
||||||
entry->args = args;
|
entry->args = args;
|
||||||
|
for (auto &[_, it] : entry->uid2lid_and_path)
|
||||||
|
entry->lid2path.emplace_back(it.first, std::move(it.second));
|
||||||
|
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
|
||||||
Uniquify(it.second.derived);
|
Uniquify(it.second.derived);
|
||||||
@ -1220,7 +1230,7 @@ std::vector<std::unique_ptr<IndexFile>> Index(
|
|||||||
|
|
||||||
// Update dependencies for the file. Do not include the file in its own
|
// Update dependencies for the file. Do not include the file in its own
|
||||||
// dependency set.
|
// dependency set.
|
||||||
for (auto & [ _, path ] : param.SeenUniqueID)
|
for (auto &[_, path] : param.SeenUniqueID)
|
||||||
if (path != entry->path && path != entry->import_file)
|
if (path != entry->path && path != entry->import_file)
|
||||||
entry->dependencies[path] = param.file2write_time[path];
|
entry->dependencies[path] = param.file2write_time[path];
|
||||||
}
|
}
|
||||||
@ -1232,34 +1242,67 @@ std::vector<std::unique_ptr<IndexFile>> Index(
|
|||||||
// |SymbolRef| is serialized this way.
|
// |SymbolRef| is serialized this way.
|
||||||
// |Use| also uses this though it has an extra field |file|,
|
// |Use| also uses this though it has an extra field |file|,
|
||||||
// which is not used by Index* so it does not need to be serialized.
|
// which is not used by Index* so it does not need to be serialized.
|
||||||
void Reflect(Reader& visitor, Reference& value) {
|
void Reflect(Reader &vis, Reference &v) {
|
||||||
if (visitor.Format() == SerializeFormat::Json) {
|
if (vis.Format() == SerializeFormat::Json) {
|
||||||
std::string t = visitor.GetString();
|
std::string t = vis.GetString();
|
||||||
char* s = const_cast<char*>(t.c_str());
|
char *s = const_cast<char *>(t.c_str());
|
||||||
value.range = Range::FromString(s);
|
v.range = Range::FromString(s);
|
||||||
s = strchr(s, '|');
|
s = strchr(s, '|');
|
||||||
value.usr = strtoull(s + 1, &s, 10);
|
v.usr = strtoull(s + 1, &s, 10);
|
||||||
value.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
|
v.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
|
||||||
value.role = static_cast<Role>(strtol(s + 1, &s, 10));
|
v.role = static_cast<Role>(strtol(s + 1, &s, 10));
|
||||||
} else {
|
} else {
|
||||||
Reflect(visitor, value.range);
|
Reflect(vis, v.range);
|
||||||
Reflect(visitor, value.usr);
|
Reflect(vis, v.usr);
|
||||||
Reflect(visitor, value.kind);
|
Reflect(vis, v.kind);
|
||||||
Reflect(visitor, value.role);
|
Reflect(vis, v.role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Reflect(Writer& visitor, Reference& value) {
|
void Reflect(Writer &vis, Reference &v) {
|
||||||
if (visitor.Format() == SerializeFormat::Json) {
|
if (vis.Format() == SerializeFormat::Json) {
|
||||||
char buf[99];
|
char buf[99];
|
||||||
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
|
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
|
||||||
value.range.ToString().c_str(), value.usr, int(value.kind),
|
v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role));
|
||||||
int(value.role));
|
|
||||||
std::string s(buf);
|
std::string s(buf);
|
||||||
Reflect(visitor, s);
|
Reflect(vis, s);
|
||||||
} else {
|
} else {
|
||||||
Reflect(visitor, value.range);
|
Reflect(vis, v.range);
|
||||||
Reflect(visitor, value.usr);
|
Reflect(vis, v.usr);
|
||||||
Reflect(visitor, value.kind);
|
Reflect(vis, v.kind);
|
||||||
Reflect(visitor, value.role);
|
Reflect(vis, v.role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reflect(Reader& vis, Use& v) {
|
||||||
|
if (vis.Format() == SerializeFormat::Json) {
|
||||||
|
std::string t = vis.GetString();
|
||||||
|
char* s = const_cast<char*>(t.c_str());
|
||||||
|
v.range = Range::FromString(s);
|
||||||
|
s = strchr(s, '|');
|
||||||
|
v.usr = strtoull(s + 1, &s, 10);
|
||||||
|
v.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
|
||||||
|
v.role = static_cast<Role>(strtol(s + 1, &s, 10));
|
||||||
|
if (*s == '|')
|
||||||
|
v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
|
||||||
|
} else {
|
||||||
|
Reflect(vis, static_cast<Reference&>(v));
|
||||||
|
Reflect(vis, v.file_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Reflect(Writer& vis, Use& v) {
|
||||||
|
if (vis.Format() == SerializeFormat::Json) {
|
||||||
|
char buf[99];
|
||||||
|
if (v.file_id == -1)
|
||||||
|
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
|
||||||
|
v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role));
|
||||||
|
else
|
||||||
|
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d|%d",
|
||||||
|
v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role),
|
||||||
|
v.file_id);
|
||||||
|
std::string s(buf);
|
||||||
|
Reflect(vis, s);
|
||||||
|
} else {
|
||||||
|
Reflect(vis, static_cast<Reference&>(v));
|
||||||
|
Reflect(vis, v.file_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,16 +52,23 @@ struct Reference {
|
|||||||
|
|
||||||
// |id,kind| refer to the referenced entity.
|
// |id,kind| refer to the referenced entity.
|
||||||
struct SymbolRef : Reference {};
|
struct SymbolRef : Reference {};
|
||||||
|
MAKE_HASHABLE(SymbolRef, t.range, t.usr, t.kind, t.role);
|
||||||
|
|
||||||
// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical
|
// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical
|
||||||
// parent.
|
// parent.
|
||||||
struct Use : Reference {
|
struct Use : Reference {
|
||||||
// |file| is used in Query* but not in Index*
|
// |file| is used in Query* but not in Index*
|
||||||
int file_id = -1;
|
int file_id = -1;
|
||||||
|
bool operator==(const Use& o) const {
|
||||||
|
return range == o.range && usr == o.usr && kind == o.kind &&
|
||||||
|
role == o.role && file_id == o.file_id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Reflect(Reader& visitor, Reference& value);
|
void Reflect(Reader& visitor, Reference& value);
|
||||||
void Reflect(Writer& visitor, Reference& value);
|
void Reflect(Writer& visitor, Reference& value);
|
||||||
|
void Reflect(Reader& visitor, Use& value);
|
||||||
|
void Reflect(Writer& visitor, Use& value);
|
||||||
|
|
||||||
MAKE_REFLECT_TYPE_PROXY2(clang::StorageClass, uint8_t);
|
MAKE_REFLECT_TYPE_PROXY2(clang::StorageClass, uint8_t);
|
||||||
|
|
||||||
@ -255,6 +262,11 @@ struct IndexFile {
|
|||||||
int64_t last_write_time = 0;
|
int64_t last_write_time = 0;
|
||||||
LanguageId language = LanguageId::Unknown;
|
LanguageId language = LanguageId::Unknown;
|
||||||
|
|
||||||
|
// uid2lid_and_path is used to generate lid2path, but not serialized.
|
||||||
|
std::unordered_map<llvm::sys::fs::UniqueID, std::pair<int, std::string>>
|
||||||
|
uid2lid_and_path;
|
||||||
|
std::vector<std::pair<int, std::string>> lid2path;
|
||||||
|
|
||||||
// The path to the translation unit cc file which caused the creation of this
|
// The path to the translation unit cc file which caused the creation of this
|
||||||
// IndexFile. When parsing a translation unit we generate many IndexFile
|
// IndexFile. When parsing a translation unit we generate many IndexFile
|
||||||
// instances (ie, each header has a separate one). When the user edits a
|
// instances (ie, each header has a separate one). When the user edits a
|
||||||
|
220
src/query.cc
220
src/query.cc
@ -17,41 +17,43 @@ MAKE_HASHABLE(Use, t.range, t.file_id);
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void AssignFileId(int file_id, SymbolRef& ref) {
|
void AssignFileId(const Lid2file_id &, int file_id, SymbolRef &ref) {
|
||||||
if (ref.kind == SymbolKind::File)
|
if (ref.kind == SymbolKind::File)
|
||||||
ref.usr = file_id;
|
ref.usr = file_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssignFileId(int file_id, Use& use) {
|
void AssignFileId(const Lid2file_id& lid2file_id, int file_id, Use& use) {
|
||||||
if (use.kind == SymbolKind::File)
|
if (use.kind == SymbolKind::File)
|
||||||
use.usr = file_id;
|
use.usr = file_id;
|
||||||
use.file_id = file_id;
|
if (use.file_id == -1)
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void AssignFileId(int file_id, T&) {}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void AssignFileId(int file_id, Maybe<T>& x) {
|
|
||||||
if (x)
|
|
||||||
AssignFileId(file_id, *x);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void AssignFileId(int file_id, std::vector<T>& xs) {
|
|
||||||
for (T& x : xs)
|
|
||||||
AssignFileId(file_id, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddRange(int file_id, std::vector<Use>& into, const std::vector<Use>& from) {
|
|
||||||
into.reserve(into.size() + from.size());
|
|
||||||
for (Use use : from) {
|
|
||||||
use.file_id = file_id;
|
use.file_id = file_id;
|
||||||
into.push_back(use);
|
else
|
||||||
}
|
use.file_id = lid2file_id.find(use.file_id)->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddRange(int _, std::vector<Usr>& into, const std::vector<Usr>& from) {
|
template <typename T>
|
||||||
|
void AssignFileId(const Lid2file_id &, int file_id, T &) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Maybe<T> &x) {
|
||||||
|
if (x)
|
||||||
|
AssignFileId(lid2file_id, file_id, *x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void AssignFileId(const Lid2file_id &lid2file_id, int file_id,
|
||||||
|
std::vector<T> &xs) {
|
||||||
|
for (T &x : xs)
|
||||||
|
AssignFileId(lid2file_id, file_id, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddRange(std::vector<Use>& into, const std::vector<Use>& from) {
|
||||||
|
into.reserve(into.size() + from.size());
|
||||||
|
for (Use use : from)
|
||||||
|
into.push_back(use);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddRange(std::vector<Usr>& into, const std::vector<Usr>& from) {
|
||||||
into.insert(into.end(), from.begin(), from.end());
|
into.insert(into.end(), from.begin(), from.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +100,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
|||||||
add_outline(decl, type.usr, SymbolKind::Type);
|
add_outline(decl, type.usr, SymbolKind::Type);
|
||||||
}
|
}
|
||||||
for (Use use : type.uses)
|
for (Use use : type.uses)
|
||||||
add_all_symbols(use, type.usr, SymbolKind::Type);
|
if (use.file_id == -1)
|
||||||
|
add_all_symbols(use, type.usr, SymbolKind::Type);
|
||||||
}
|
}
|
||||||
for (auto& it: indexed.usr2func) {
|
for (auto& it: indexed.usr2func) {
|
||||||
const IndexFunc& func = it.second;
|
const IndexFunc& func = it.second;
|
||||||
@ -110,18 +113,19 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
|||||||
add_all_symbols(use, func.usr, SymbolKind::Func);
|
add_all_symbols(use, func.usr, SymbolKind::Func);
|
||||||
add_outline(use, func.usr, SymbolKind::Func);
|
add_outline(use, func.usr, SymbolKind::Func);
|
||||||
}
|
}
|
||||||
for (Use use : func.uses) {
|
for (Use use : func.uses)
|
||||||
// Make ranges of implicit function calls larger (spanning one more column
|
if (use.file_id == -1) {
|
||||||
// to the left/right). This is hacky but useful. e.g.
|
// Make ranges of implicit function calls larger (spanning one more
|
||||||
// textDocument/definition on the space/semicolon in `A a;` or `return
|
// column to the left/right). This is hacky but useful. e.g.
|
||||||
// 42;` will take you to the constructor.
|
// textDocument/definition on the space/semicolon in `A a;` or `return
|
||||||
if (use.role & Role::Implicit) {
|
// 42;` will take you to the constructor.
|
||||||
if (use.range.start.column > 0)
|
if (use.role & Role::Implicit) {
|
||||||
use.range.start.column--;
|
if (use.range.start.column > 0)
|
||||||
use.range.end.column++;
|
use.range.start.column--;
|
||||||
|
use.range.end.column++;
|
||||||
|
}
|
||||||
|
add_all_symbols(use, func.usr, SymbolKind::Func);
|
||||||
}
|
}
|
||||||
add_all_symbols(use, func.usr, SymbolKind::Func);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (auto& it : indexed.usr2var) {
|
for (auto& it : indexed.usr2var) {
|
||||||
const IndexVar& var = it.second;
|
const IndexVar& var = it.second;
|
||||||
@ -134,7 +138,8 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
|||||||
add_outline(decl, var.usr, SymbolKind::Var);
|
add_outline(decl, var.usr, SymbolKind::Var);
|
||||||
}
|
}
|
||||||
for (Use use : var.uses)
|
for (Use use : var.uses)
|
||||||
add_all_symbols(use, var.usr, SymbolKind::Var);
|
if (use.file_id == -1)
|
||||||
|
add_all_symbols(use, var.usr, SymbolKind::Var);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(def.outline.begin(), def.outline.end(),
|
std::sort(def.outline.begin(), def.outline.end(),
|
||||||
@ -162,19 +167,16 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q>& def_list, Q&& def) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// ----------------------
|
|
||||||
// INDEX THREAD FUNCTIONS
|
|
||||||
// ----------------------
|
|
||||||
|
|
||||||
// static
|
|
||||||
IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
IndexUpdate IndexUpdate::CreateDelta(IndexFile* previous,
|
||||||
IndexFile* current) {
|
IndexFile* current) {
|
||||||
IndexUpdate r;
|
IndexUpdate r;
|
||||||
static IndexFile empty(llvm::sys::fs::UniqueID(0, 0), current->path,
|
static IndexFile empty(llvm::sys::fs::UniqueID(0, 0), current->path,
|
||||||
"<empty>");
|
"<empty>");
|
||||||
if (!previous)
|
if (previous)
|
||||||
|
r.prev_lid2path = std::move(previous->lid2path);
|
||||||
|
else
|
||||||
previous = ∅
|
previous = ∅
|
||||||
|
r.lid2path = std::move(current->lid2path);
|
||||||
r.files_def_update = BuildFileDefUpdate(std::move(*current));
|
r.files_def_update = BuildFileDefUpdate(std::move(*current));
|
||||||
|
|
||||||
r.funcs_hint = int(current->usr2func.size() - previous->usr2func.size());
|
r.funcs_hint = int(current->usr2func.size() - previous->usr2func.size());
|
||||||
@ -282,23 +284,59 @@ void DB::RemoveUsrs(SymbolKind kind,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DB::ApplyIndexUpdate(IndexUpdate* u) {
|
void DB::ApplyIndexUpdate(IndexUpdate *u) {
|
||||||
#define REMOVE_ADD(C, F) \
|
#define REMOVE_ADD(C, F) \
|
||||||
for (auto& it : u->C##s_##F) { \
|
for (auto &it : u->C##s_##F) { \
|
||||||
auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \
|
auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \
|
||||||
if (R.second) \
|
if (R.second) \
|
||||||
C##s.emplace_back().usr = it.first; \
|
C##s.emplace_back().usr = it.first; \
|
||||||
auto& entity = C##s[R.first->second]; \
|
auto &entity = C##s[R.first->second]; \
|
||||||
AssignFileId(u->file_id, it.second.first); \
|
AssignFileId(prev_lid2file_id, u->file_id, it.second.first); \
|
||||||
RemoveRange(entity.F, it.second.first); \
|
RemoveRange(entity.F, it.second.first); \
|
||||||
AssignFileId(u->file_id, it.second.second); \
|
AssignFileId(lid2file_id, u->file_id, it.second.second); \
|
||||||
AddRange(u->file_id, entity.F, it.second.second); \
|
AddRange(entity.F, it.second.second); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map<int, int> prev_lid2file_id, lid2file_id;
|
||||||
|
for (auto & [ lid, path ] : u->prev_lid2path)
|
||||||
|
prev_lid2file_id[lid] = GetFileId(path);
|
||||||
|
for (auto & [ lid, path ] : u->lid2path)
|
||||||
|
lid2file_id[lid] = GetFileId(path);
|
||||||
|
|
||||||
|
auto UpdateUses = [&](Usr usr, SymbolKind kind,
|
||||||
|
llvm::DenseMap<WrappedUsr, int> &entity_usr,
|
||||||
|
auto &entities, auto &p) {
|
||||||
|
auto R = entity_usr.try_emplace({usr}, entity_usr.size());
|
||||||
|
if (R.second)
|
||||||
|
vars.emplace_back().usr = usr;
|
||||||
|
auto &entity = entities[R.first->second];
|
||||||
|
for (Use &use : p.first) {
|
||||||
|
if (use.file_id == -1)
|
||||||
|
use.file_id = u->file_id;
|
||||||
|
else {
|
||||||
|
use.file_id = prev_lid2file_id.find(use.file_id)->second;
|
||||||
|
files[use.file_id]
|
||||||
|
.symbol2refcnt[SymbolRef{{use.range, usr, kind, use.role}}]--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RemoveRange(entity.uses, p.first);
|
||||||
|
for (Use &use : p.second) {
|
||||||
|
if (use.file_id == -1)
|
||||||
|
use.file_id = u->file_id;
|
||||||
|
else {
|
||||||
|
use.file_id = lid2file_id.find(use.file_id)->second;
|
||||||
|
files[use.file_id]
|
||||||
|
.symbol2refcnt[SymbolRef{{use.range, usr, kind, use.role}}]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AddRange(entity.uses, p.second);
|
||||||
|
};
|
||||||
|
|
||||||
if (u->files_removed)
|
if (u->files_removed)
|
||||||
files[name2file_id[LowerPathIfInsensitive(*u->files_removed)]].def =
|
files[name2file_id[LowerPathIfInsensitive(*u->files_removed)]].def =
|
||||||
std::nullopt;
|
std::nullopt;
|
||||||
u->file_id = u->files_def_update ? Update(std::move(*u->files_def_update)) : -1;
|
u->file_id =
|
||||||
|
u->files_def_update ? Update(std::move(*u->files_def_update)) : -1;
|
||||||
|
|
||||||
const double grow = 1.3;
|
const double grow = 1.3;
|
||||||
size_t t;
|
size_t t;
|
||||||
@ -309,10 +347,11 @@ void DB::ApplyIndexUpdate(IndexUpdate* u) {
|
|||||||
func_usr.reserve(t);
|
func_usr.reserve(t);
|
||||||
}
|
}
|
||||||
RemoveUsrs(SymbolKind::Func, u->file_id, u->funcs_removed);
|
RemoveUsrs(SymbolKind::Func, u->file_id, u->funcs_removed);
|
||||||
Update(u->file_id, std::move(u->funcs_def_update));
|
Update(lid2file_id, u->file_id, std::move(u->funcs_def_update));
|
||||||
REMOVE_ADD(func, declarations);
|
REMOVE_ADD(func, declarations);
|
||||||
REMOVE_ADD(func, derived);
|
REMOVE_ADD(func, derived);
|
||||||
REMOVE_ADD(func, uses);
|
for (auto & [ usr, p ] : u->funcs_uses)
|
||||||
|
UpdateUses(usr, SymbolKind::Func, func_usr, funcs, p);
|
||||||
|
|
||||||
if ((t = types.size() + u->types_hint) > types.capacity()) {
|
if ((t = types.size() + u->types_hint) > types.capacity()) {
|
||||||
t = size_t(t * grow);
|
t = size_t(t * grow);
|
||||||
@ -320,11 +359,12 @@ void DB::ApplyIndexUpdate(IndexUpdate* u) {
|
|||||||
type_usr.reserve(t);
|
type_usr.reserve(t);
|
||||||
}
|
}
|
||||||
RemoveUsrs(SymbolKind::Type, u->file_id, u->types_removed);
|
RemoveUsrs(SymbolKind::Type, u->file_id, u->types_removed);
|
||||||
Update(u->file_id, std::move(u->types_def_update));
|
Update(lid2file_id, u->file_id, std::move(u->types_def_update));
|
||||||
REMOVE_ADD(type, declarations);
|
REMOVE_ADD(type, declarations);
|
||||||
REMOVE_ADD(type, derived);
|
REMOVE_ADD(type, derived);
|
||||||
REMOVE_ADD(type, instances);
|
REMOVE_ADD(type, instances);
|
||||||
REMOVE_ADD(type, uses);
|
for (auto & [ usr, p ] : u->types_uses)
|
||||||
|
UpdateUses(usr, SymbolKind::Type, type_usr, types, p);
|
||||||
|
|
||||||
if ((t = vars.size() + u->vars_hint) > vars.capacity()) {
|
if ((t = vars.size() + u->vars_hint) > vars.capacity()) {
|
||||||
t = size_t(t * grow);
|
t = size_t(t * grow);
|
||||||
@ -332,30 +372,37 @@ void DB::ApplyIndexUpdate(IndexUpdate* u) {
|
|||||||
var_usr.reserve(t);
|
var_usr.reserve(t);
|
||||||
}
|
}
|
||||||
RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed);
|
RemoveUsrs(SymbolKind::Var, u->file_id, u->vars_removed);
|
||||||
Update(u->file_id, std::move(u->vars_def_update));
|
Update(lid2file_id, u->file_id, std::move(u->vars_def_update));
|
||||||
REMOVE_ADD(var, declarations);
|
REMOVE_ADD(var, declarations);
|
||||||
REMOVE_ADD(var, uses);
|
for (auto & [ usr, p ] : u->vars_uses)
|
||||||
|
UpdateUses(usr, SymbolKind::Var, var_usr, vars, p);
|
||||||
|
|
||||||
#undef REMOVE_ADD
|
#undef REMOVE_ADD
|
||||||
}
|
}
|
||||||
|
|
||||||
int DB::Update(QueryFile::DefUpdate&& u) {
|
int DB::GetFileId(const std::string& path) {
|
||||||
int id = files.size();
|
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(path));
|
||||||
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.first.path), id);
|
if (it.second) {
|
||||||
if (it.second)
|
int id = files.size();
|
||||||
files.emplace_back().id = id;
|
it.first->second = files.emplace_back().id = id;
|
||||||
QueryFile& existing = files[it.first->second];
|
}
|
||||||
existing.def = u.first;
|
return it.first->second;
|
||||||
return existing.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
|
int DB::Update(QueryFile::DefUpdate&& u) {
|
||||||
for (auto& u : us) {
|
int file_id = GetFileId(u.first.path);
|
||||||
|
files[file_id].def = u.first;
|
||||||
|
return file_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||||
|
std::vector<std::pair<Usr, QueryFunc::Def>> &&us) {
|
||||||
|
for (auto &u : us) {
|
||||||
auto& def = u.second;
|
auto& def = u.second;
|
||||||
assert(def.detailed_name[0]);
|
assert(def.detailed_name[0]);
|
||||||
AssignFileId(file_id, def.spell);
|
AssignFileId(lid2file_id, file_id, def.spell);
|
||||||
AssignFileId(file_id, def.extent);
|
AssignFileId(lid2file_id, file_id, def.extent);
|
||||||
AssignFileId(file_id, def.callees);
|
AssignFileId(lid2file_id, file_id, def.callees);
|
||||||
auto R = func_usr.try_emplace({u.first}, func_usr.size());
|
auto R = func_usr.try_emplace({u.first}, func_usr.size());
|
||||||
if (R.second)
|
if (R.second)
|
||||||
funcs.emplace_back();
|
funcs.emplace_back();
|
||||||
@ -366,12 +413,13 @@ void DB::Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us) {
|
void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||||
for (auto& u : us) {
|
std::vector<std::pair<Usr, QueryType::Def>> &&us) {
|
||||||
|
for (auto &u : us) {
|
||||||
auto& def = u.second;
|
auto& def = u.second;
|
||||||
assert(def.detailed_name[0]);
|
assert(def.detailed_name[0]);
|
||||||
AssignFileId(file_id, def.spell);
|
AssignFileId(lid2file_id, file_id, def.spell);
|
||||||
AssignFileId(file_id, def.extent);
|
AssignFileId(lid2file_id, file_id, def.extent);
|
||||||
auto R = type_usr.try_emplace({u.first}, type_usr.size());
|
auto R = type_usr.try_emplace({u.first}, type_usr.size());
|
||||||
if (R.second)
|
if (R.second)
|
||||||
types.emplace_back();
|
types.emplace_back();
|
||||||
@ -379,16 +427,16 @@ void DB::Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us) {
|
|||||||
existing.usr = u.first;
|
existing.usr = u.first;
|
||||||
if (!TryReplaceDef(existing.def, std::move(def)))
|
if (!TryReplaceDef(existing.def, std::move(def)))
|
||||||
existing.def.push_back(std::move(def));
|
existing.def.push_back(std::move(def));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DB::Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us) {
|
void DB::Update(const Lid2file_id &lid2file_id, int file_id,
|
||||||
for (auto& u : us) {
|
std::vector<std::pair<Usr, QueryVar::Def>> &&us) {
|
||||||
|
for (auto &u : us) {
|
||||||
auto& def = u.second;
|
auto& def = u.second;
|
||||||
assert(def.detailed_name[0]);
|
assert(def.detailed_name[0]);
|
||||||
AssignFileId(file_id, def.spell);
|
AssignFileId(lid2file_id, file_id, def.spell);
|
||||||
AssignFileId(file_id, def.extent);
|
AssignFileId(lid2file_id, file_id, def.extent);
|
||||||
auto R = var_usr.try_emplace({u.first}, var_usr.size());
|
auto R = var_usr.try_emplace({u.first}, var_usr.size());
|
||||||
if (R.second)
|
if (R.second)
|
||||||
vars.emplace_back();
|
vars.emplace_back();
|
||||||
|
20
src/query.h
20
src/query.h
@ -28,6 +28,7 @@ struct QueryFile {
|
|||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
std::optional<Def> def;
|
std::optional<Def> def;
|
||||||
|
std::unordered_map<SymbolRef, int> symbol2refcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Q, typename QDef>
|
template <typename Q, typename QDef>
|
||||||
@ -85,6 +86,9 @@ struct IndexUpdate {
|
|||||||
// Dummy one to refresh all semantic highlight.
|
// Dummy one to refresh all semantic highlight.
|
||||||
bool refresh = false;
|
bool refresh = false;
|
||||||
|
|
||||||
|
decltype(IndexFile::lid2path) prev_lid2path;
|
||||||
|
decltype(IndexFile::lid2path) lid2path;
|
||||||
|
|
||||||
// File updates.
|
// File updates.
|
||||||
std::optional<std::string> files_removed;
|
std::optional<std::string> files_removed;
|
||||||
std::optional<QueryFile::DefUpdate> files_def_update;
|
std::optional<QueryFile::DefUpdate> files_def_update;
|
||||||
@ -125,6 +129,8 @@ struct llvm::DenseMapInfo<WrappedUsr> {
|
|||||||
static bool isEqual(WrappedUsr l, WrappedUsr r) { return l.usr == r.usr; }
|
static bool isEqual(WrappedUsr l, WrappedUsr r) { return l.usr == r.usr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Lid2file_id = std::unordered_map<int, int>;
|
||||||
|
|
||||||
// The query database is heavily optimized for fast queries. It is stored
|
// The query database is heavily optimized for fast queries. It is stored
|
||||||
// in-memory.
|
// in-memory.
|
||||||
struct DB {
|
struct DB {
|
||||||
@ -135,15 +141,17 @@ struct DB {
|
|||||||
std::vector<QueryType> types;
|
std::vector<QueryType> types;
|
||||||
std::vector<QueryVar> vars;
|
std::vector<QueryVar> vars;
|
||||||
|
|
||||||
// Marks the given Usrs as invalid.
|
void RemoveUsrs(SymbolKind kind, int file_id, const std::vector<Usr>& to_remove);
|
||||||
void RemoveUsrs(SymbolKind usr_kind, const std::vector<Usr>& to_remove);
|
|
||||||
void RemoveUsrs(SymbolKind usr_kind, int file_id, const std::vector<Usr>& to_remove);
|
|
||||||
// Insert the contents of |update| into |db|.
|
// Insert the contents of |update| into |db|.
|
||||||
void ApplyIndexUpdate(IndexUpdate* update);
|
void ApplyIndexUpdate(IndexUpdate* update);
|
||||||
|
int GetFileId(const std::string& path);
|
||||||
int Update(QueryFile::DefUpdate&& u);
|
int Update(QueryFile::DefUpdate&& u);
|
||||||
void Update(int file_id, std::vector<std::pair<Usr, QueryType::Def>>&& us);
|
void Update(const Lid2file_id &, int file_id,
|
||||||
void Update(int file_id, std::vector<std::pair<Usr, QueryFunc::Def>>&& us);
|
std::vector<std::pair<Usr, QueryType::Def>> &&us);
|
||||||
void Update(int file_id, std::vector<std::pair<Usr, QueryVar::Def>>&& us);
|
void Update(const Lid2file_id &, int file_id,
|
||||||
|
std::vector<std::pair<Usr, QueryFunc::Def>> &&us);
|
||||||
|
void Update(const Lid2file_id &, int file_id,
|
||||||
|
std::vector<std::pair<Usr, QueryVar::Def>> &&us);
|
||||||
std::string_view GetSymbolName(SymbolIdx sym, bool qualified);
|
std::string_view GetSymbolName(SymbolIdx sym, bool qualified);
|
||||||
|
|
||||||
bool HasFunc(Usr usr) const { return func_usr.count({usr}); }
|
bool HasFunc(Usr usr) const { return func_usr.count({usr}); }
|
||||||
|
@ -319,10 +319,12 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const SymbolRef& sym : file->def->all_symbols) {
|
for (SymbolRef sym : file->def->all_symbols)
|
||||||
if (sym.range.Contains(ls_pos.line, ls_pos.character))
|
if (sym.range.Contains(ls_pos.line, ls_pos.character))
|
||||||
symbols.push_back(sym);
|
symbols.push_back(sym);
|
||||||
}
|
for (auto[sym, refcnt] : file->symbol2refcnt)
|
||||||
|
if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character))
|
||||||
|
symbols.push_back(sym);
|
||||||
|
|
||||||
// Order shorter ranges first, since they are more detailed/precise. This is
|
// Order shorter ranges first, since they are more detailed/precise. This is
|
||||||
// important for macros which generate code so that we can resolving the
|
// important for macros which generate code so that we can resolving the
|
||||||
@ -340,8 +342,10 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile* working_file,
|
|||||||
int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
|
int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
|
||||||
if (t)
|
if (t)
|
||||||
return t < 0;
|
return t < 0;
|
||||||
t = (a.role & Role::Definition) - (b.role & Role::Definition);
|
// MacroExpansion
|
||||||
if (t)
|
if ((t = (a.role & Role::Dynamic) - (b.role & Role::Dynamic)))
|
||||||
|
return t > 0;
|
||||||
|
if ((t = (a.role & Role::Definition) - (b.role & Role::Definition)))
|
||||||
return t > 0;
|
return t > 0;
|
||||||
// operator> orders Var/Func before Type.
|
// operator> orders Var/Func before Type.
|
||||||
t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
|
t = static_cast<int>(a.kind) - static_cast<int>(b.kind);
|
||||||
|
@ -330,6 +330,7 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
|
|||||||
if (!gTestOutputMode) {
|
if (!gTestOutputMode) {
|
||||||
REFLECT_MEMBER(last_write_time);
|
REFLECT_MEMBER(last_write_time);
|
||||||
REFLECT_MEMBER(language);
|
REFLECT_MEMBER(language);
|
||||||
|
REFLECT_MEMBER(lid2path);
|
||||||
REFLECT_MEMBER(import_file);
|
REFLECT_MEMBER(import_file);
|
||||||
REFLECT_MEMBER(args);
|
REFLECT_MEMBER(args);
|
||||||
REFLECT_MEMBER(dependencies);
|
REFLECT_MEMBER(dependencies);
|
||||||
|
Loading…
Reference in New Issue
Block a user