💥 Rename FunctionName -> functionName, VarName -> var_name

This commit is contained in:
Fangrui Song 2019-08-22 10:12:03 -07:00
parent 62fbde7873
commit 61a1071634
62 changed files with 2983 additions and 2968 deletions

View File

@ -14,99 +14,99 @@
using namespace clang;
namespace ccls {
std::string PathFromFileEntry(const FileEntry &file) {
StringRef Name = file.tryGetRealPathName();
if (Name.empty())
Name = file.getName();
std::string ret = NormalizePath(Name);
std::string pathFromFileEntry(const FileEntry &file) {
StringRef name = file.tryGetRealPathName();
if (name.empty())
name = file.getName();
std::string ret = normalizePath(name);
// Resolve symlinks outside of workspace folders, e.g. /usr/include/c++/7.3.0
return NormalizeFolder(ret) ? ret : RealPath(ret);
return normalizeFolder(ret) ? ret : realPath(ret);
}
static Pos Decomposed2LineAndCol(const SourceManager &SM,
std::pair<FileID, unsigned> I) {
int l = (int)SM.getLineNumber(I.first, I.second) - 1,
c = (int)SM.getColumnNumber(I.first, I.second) - 1;
bool Invalid = false;
StringRef Buf = SM.getBufferData(I.first, &Invalid);
if (!Invalid) {
StringRef P = Buf.substr(I.second - c, c);
static Pos decomposed2LineAndCol(const SourceManager &sm,
std::pair<FileID, unsigned> i) {
int l = (int)sm.getLineNumber(i.first, i.second) - 1,
c = (int)sm.getColumnNumber(i.first, i.second) - 1;
bool invalid = false;
StringRef buf = sm.getBufferData(i.first, &invalid);
if (!invalid) {
StringRef p = buf.substr(i.second - c, c);
c = 0;
for (size_t i = 0; i < P.size(); )
if (c++, (uint8_t)P[i++] >= 128)
while (i < P.size() && (uint8_t)P[i] >= 128 && (uint8_t)P[i] < 192)
for (size_t i = 0; i < p.size();)
if (c++, (uint8_t)p[i++] >= 128)
while (i < p.size() && (uint8_t)p[i] >= 128 && (uint8_t)p[i] < 192)
i++;
}
return {(uint16_t)std::min<int>(l, UINT16_MAX),
(int16_t)std::min<int>(c, INT16_MAX)};
}
Range FromCharSourceRange(const SourceManager &SM, const LangOptions &LangOpts,
CharSourceRange R,
llvm::sys::fs::UniqueID *UniqueID) {
SourceLocation BLoc = R.getBegin(), ELoc = R.getEnd();
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc),
EInfo = SM.getDecomposedLoc(ELoc);
if (R.isTokenRange())
EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, LangOpts);
if (UniqueID) {
if (const FileEntry *F = SM.getFileEntryForID(BInfo.first))
*UniqueID = F->getUniqueID();
Range fromCharSourceRange(const SourceManager &sm, const LangOptions &lang,
CharSourceRange csr,
llvm::sys::fs::UniqueID *uniqueID) {
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);
*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 R, llvm::sys::fs::UniqueID *UniqueID) {
return FromCharSourceRange(SM, Lang, CharSourceRange::getCharRange(R),
UniqueID);
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 R, llvm::sys::fs::UniqueID *UniqueID) {
return FromCharSourceRange(SM, Lang, CharSourceRange::getTokenRange(R),
UniqueID);
Range fromTokenRange(const SourceManager &sm, const LangOptions &lang,
SourceRange sr, llvm::sys::fs::UniqueID *uniqueID) {
return fromCharSourceRange(sm, lang, CharSourceRange::getTokenRange(sr),
uniqueID);
}
Range FromTokenRangeDefaulted(const SourceManager &SM, const LangOptions &Lang,
SourceRange R, const FileEntry *FE, Range range) {
auto I = SM.getDecomposedLoc(SM.getExpansionLoc(R.getBegin()));
if (SM.getFileEntryForID(I.first) == FE)
range.start = Decomposed2LineAndCol(SM, I);
SourceLocation L = SM.getExpansionLoc(R.getEnd());
I = SM.getDecomposedLoc(L);
if (SM.getFileEntryForID(I.first) == FE) {
I.second += Lexer::MeasureTokenLength(L, SM, Lang);
range.end = Decomposed2LineAndCol(SM, I);
Range fromTokenRangeDefaulted(const SourceManager &sm, const LangOptions &lang,
SourceRange sr, const FileEntry *fe, Range range) {
auto decomposed = sm.getDecomposedLoc(sm.getExpansionLoc(sr.getBegin()));
if (sm.getFileEntryForID(decomposed.first) == fe)
range.start = decomposed2LineAndCol(sm, decomposed);
SourceLocation sl = sm.getExpansionLoc(sr.getEnd());
decomposed = sm.getDecomposedLoc(sl);
if (sm.getFileEntryForID(decomposed.first) == fe) {
decomposed.second += Lexer::MeasureTokenLength(sl, sm, lang);
range.end = decomposed2LineAndCol(sm, decomposed);
}
return range;
}
std::unique_ptr<CompilerInvocation>
BuildCompilerInvocation(const std::string &main, std::vector<const char *> args,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
buildCompilerInvocation(const std::string &main, std::vector<const char *> args,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs) {
std::string save = "-resource-dir=" + g_config->clang.resourceDir;
args.push_back(save.c_str());
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
IntrusiveRefCntPtr<DiagnosticsEngine> diags(
CompilerInstance::createDiagnostics(new DiagnosticOptions,
new IgnoringDiagConsumer, true));
std::unique_ptr<CompilerInvocation> CI =
createInvocationFromCommandLine(args, Diags, VFS);
if (CI) {
CI->getDiagnosticOpts().IgnoreWarnings = true;
CI->getFrontendOpts().DisableFree = false;
CI->getLangOpts()->SpellChecking = false;
auto &IS = CI->getFrontendOpts().Inputs;
if (IS.size())
IS[0] = FrontendInputFile(main, IS[0].getKind(), IS[0].isSystem());
std::unique_ptr<CompilerInvocation> ci =
createInvocationFromCommandLine(args, diags, vfs);
if (ci) {
ci->getDiagnosticOpts().IgnoreWarnings = true;
ci->getFrontendOpts().DisableFree = false;
ci->getLangOpts()->SpellChecking = false;
auto &isec = ci->getFrontendOpts().Inputs;
if (isec.size())
isec[0] = FrontendInputFile(main, isec[0].getKind(), isec[0].isSystem());
}
return CI;
return ci;
}
// clang::BuiltinType::getName without PrintingPolicy
const char *ClangBuiltinTypeName(int kind) {
const char *clangBuiltinTypeName(int kind) {
switch (BuiltinType::Kind(kind)) {
case BuiltinType::Void:
return "void";

View File

@ -5,8 +5,8 @@
#include "position.hh"
#include <clang/Basic/LangOptions.h>
#include <clang/Basic/FileManager.h>
#include <clang/Basic/LangOptions.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Frontend/CompilerInstance.h>
@ -18,30 +18,29 @@ namespace vfs = clang::vfs;
#endif
namespace ccls {
std::string PathFromFileEntry(const clang::FileEntry &file);
std::string pathFromFileEntry(const clang::FileEntry &file);
Range FromCharSourceRange(const clang::SourceManager &SM,
const clang::LangOptions &LangOpts,
clang::CharSourceRange R,
llvm::sys::fs::UniqueID *UniqueID = nullptr);
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 &LangOpts, clang::SourceRange R,
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);
Range FromTokenRange(const clang::SourceManager &SM,
const clang::LangOptions &LangOpts, clang::SourceRange R,
llvm::sys::fs::UniqueID *UniqueID = nullptr);
Range fromTokenRange(const clang::SourceManager &sm,
const clang::LangOptions &lang, clang::SourceRange sr,
llvm::sys::fs::UniqueID *uniqueID = nullptr);
Range FromTokenRangeDefaulted(const clang::SourceManager &SM,
const clang::LangOptions &Lang,
clang::SourceRange R, const clang::FileEntry *FE,
Range fromTokenRangeDefaulted(const clang::SourceManager &sm,
const clang::LangOptions &lang,
clang::SourceRange sr, const clang::FileEntry *fe,
Range range);
std::unique_ptr<clang::CompilerInvocation>
BuildCompilerInvocation(const std::string &main,
std::vector<const char *> args,
buildCompilerInvocation(const std::string &main, std::vector<const char *> args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS);
const char *ClangBuiltinTypeName(int);
const char *clangBuiltinTypeName(int);
} // namespace ccls

View File

@ -6,7 +6,7 @@
namespace ccls {
Config *g_config;
void DoPathMapping(std::string &arg) {
void doPathMapping(std::string &arg) {
for (const std::string &mapping : g_config->clang.pathMappings) {
auto sep = mapping.find('>');
if (sep != std::string::npos) {
@ -16,4 +16,4 @@ void DoPathMapping(std::string &arg) {
}
}
}
}
} // namespace ccls

View File

@ -256,7 +256,8 @@ struct Config {
// lines, include the initializer in detailed_name.
int maxInitializerLines = 5;
// If not 0, a file will be indexed in each tranlation unit that includes it.
// If not 0, a file will be indexed in each tranlation unit that includes
// it.
int multiVersion = 0;
// If multiVersion != 0, files that match blacklist but not whitelist will
@ -351,5 +352,5 @@ REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory,
extern Config *g_config;
void DoPathMapping(std::string &arg);
}
void doPathMapping(std::string &arg);
} // namespace ccls

View File

@ -9,16 +9,16 @@ using namespace llvm;
#include <set>
#include <vector>
void GetFilesInFolder(std::string folder, bool recursive, bool dir_prefix,
void getFilesInFolder(std::string folder, bool recursive, bool dir_prefix,
const std::function<void(const std::string &)> &handler) {
ccls::EnsureEndsInSlash(folder);
sys::fs::file_status Status;
if (sys::fs::status(folder, Status, true))
ccls::ensureEndsInSlash(folder);
sys::fs::file_status status;
if (sys::fs::status(folder, status, true))
return;
sys::fs::UniqueID ID;
sys::fs::UniqueID id;
std::vector<std::string> curr{folder};
std::vector<std::pair<std::string, sys::fs::file_status>> succ;
std::set<sys::fs::UniqueID> seen{Status.getUniqueID()};
std::set<sys::fs::UniqueID> seen{status.getUniqueID()};
while (curr.size() || succ.size()) {
if (curr.empty()) {
for (auto &it : succ)
@ -29,29 +29,29 @@ void GetFilesInFolder(std::string folder, bool recursive, bool dir_prefix,
std::error_code ec;
std::string folder1 = curr.back();
curr.pop_back();
for (sys::fs::directory_iterator I(folder1, ec, false), E; I != E && !ec;
I.increment(ec)) {
std::string path = I->path(), filename = sys::path::filename(path);
for (sys::fs::directory_iterator i(folder1, ec, false), e; i != e && !ec;
i.increment(ec)) {
std::string path = i->path(), filename = sys::path::filename(path);
if ((filename[0] == '.' && filename != ".ccls") ||
sys::fs::status(path, Status, false))
sys::fs::status(path, status, false))
continue;
if (sys::fs::is_symlink_file(Status)) {
if (sys::fs::status(path, Status, true))
if (sys::fs::is_symlink_file(status)) {
if (sys::fs::status(path, status, true))
continue;
if (sys::fs::is_directory(Status)) {
if (sys::fs::is_directory(status)) {
if (recursive)
succ.emplace_back(path, Status);
succ.emplace_back(path, status);
continue;
}
}
if (sys::fs::is_regular_file(Status)) {
if (sys::fs::is_regular_file(status)) {
if (!dir_prefix)
path = path.substr(folder.size());
handler(sys::path::convert_to_slash(path));
} else if (recursive && sys::fs::is_directory(Status) &&
!seen.count(ID = Status.getUniqueID())) {
} else if (recursive && sys::fs::is_directory(status) &&
!seen.count(id = status.getUniqueID())) {
curr.push_back(path);
seen.insert(ID);
seen.insert(id);
}
}
}

View File

@ -9,7 +9,6 @@
#include <functional>
#include <string>
void GetFilesInFolder(std::string folder,
bool recursive,
void getFilesInFolder(std::string folder, bool recursive,
bool add_folder_to_path,
const std::function<void(const std::string &)> &handler);

View File

@ -13,7 +13,7 @@ namespace {
enum CharClass { Other, Lower, Upper };
enum CharRole { None, Tail, Head };
CharClass GetCharClass(int c) {
CharClass getCharClass(int c) {
if (islower(c))
return Lower;
if (isupper(c))
@ -21,12 +21,12 @@ CharClass GetCharClass(int c) {
return Other;
}
void CalculateRoles(std::string_view s, int roles[], int *class_set) {
void calculateRoles(std::string_view s, int roles[], int *class_set) {
if (s.empty()) {
*class_set = 0;
return;
}
CharClass pre = Other, cur = GetCharClass(s[0]), suc;
CharClass pre = Other, cur = getCharClass(s[0]), suc;
*class_set = 1 << cur;
auto fn = [&]() {
if (cur == Other)
@ -37,7 +37,7 @@ void CalculateRoles(std::string_view s, int roles[], int *class_set) {
: Tail;
};
for (size_t i = 0; i < s.size() - 1; i++) {
suc = GetCharClass(s[i + 1]);
suc = getCharClass(s[i + 1]);
*class_set |= 1 << suc;
roles[i] = fn();
pre = cur;
@ -47,7 +47,7 @@ void CalculateRoles(std::string_view s, int roles[], int *class_set) {
}
} // namespace
int FuzzyMatcher::MissScore(int j, bool last) {
int FuzzyMatcher::missScore(int j, bool last) {
int s = -3;
if (last)
s -= 10;
@ -56,7 +56,7 @@ int FuzzyMatcher::MissScore(int j, bool last) {
return s;
}
int FuzzyMatcher::MatchScore(int i, int j, bool last) {
int FuzzyMatcher::matchScore(int i, int j, bool last) {
int s = 0;
// Case matching.
if (pat[i] == text[j]) {
@ -81,7 +81,7 @@ int FuzzyMatcher::MatchScore(int i, int j, bool last) {
}
FuzzyMatcher::FuzzyMatcher(std::string_view pattern, int sensitivity) {
CalculateRoles(pattern, pat_role, &pat_set);
calculateRoles(pattern, pat_role, &pat_set);
if (sensitivity == 1)
sensitivity = pat_set & 1 << Upper ? 2 : 0;
case_sensitivity = sensitivity;
@ -95,7 +95,7 @@ FuzzyMatcher::FuzzyMatcher(std::string_view pattern, int sensitivity) {
}
}
int FuzzyMatcher::Match(std::string_view text, bool strict) {
int FuzzyMatcher::match(std::string_view text, bool strict) {
if (pat.empty() != text.empty())
return kMinScore;
int n = int(text.size());
@ -104,12 +104,12 @@ int FuzzyMatcher::Match(std::string_view text, bool strict) {
this->text = text;
for (int i = 0; i < n; i++)
low_text[i] = (char)::tolower(text[i]);
CalculateRoles(text, text_role, &text_set);
calculateRoles(text, text_role, &text_set);
if (strict && n && !!pat_role[0] != !!text_role[0])
return kMinScore;
dp[0][0][0] = dp[0][0][1] = 0;
for (int j = 0; j < n; j++) {
dp[0][j + 1][0] = dp[0][j][0] + MissScore(j, false);
dp[0][j + 1][0] = dp[0][j][0] + missScore(j, false);
dp[0][j + 1][1] = kMinScore * 2;
}
for (int i = 0; i < int(pat.size()); i++) {
@ -117,16 +117,16 @@ int FuzzyMatcher::Match(std::string_view text, bool strict) {
int(*cur)[2] = dp[(i + 1) & 1];
cur[i][0] = cur[i][1] = kMinScore;
for (int j = i; j < n; j++) {
cur[j + 1][0] = std::max(cur[j][0] + MissScore(j, false),
cur[j][1] + MissScore(j, true));
cur[j + 1][0] = std::max(cur[j][0] + missScore(j, false),
cur[j][1] + missScore(j, true));
// For the first char of pattern, apply extra restriction to filter bad
// candidates (e.g. |int| in |PRINT|)
cur[j + 1][1] = (case_sensitivity ? pat[i] == text[j]
: low_pat[i] == low_text[j] &&
(i || text_role[j] != Tail ||
pat[i] == text[j]))
? std::max(pre[j][0] + MatchScore(i, j, false),
pre[j][1] + MatchScore(i, j, true))
? std::max(pre[j][0] + matchScore(i, j, false),
pre[j][1] + matchScore(i, j, true))
: kMinScore * 2;
}
}

View File

@ -17,7 +17,7 @@ public:
constexpr static int kMinScore = INT_MIN / 4;
FuzzyMatcher(std::string_view pattern, int case_sensitivity);
int Match(std::string_view text, bool strict);
int match(std::string_view text, bool strict);
private:
int case_sensitivity;
@ -28,7 +28,7 @@ private:
int pat_role[kMaxPat], text_role[kMaxText];
int dp[2][kMaxText + 1][2];
int MatchScore(int i, int j, bool last);
int MissScore(int j, bool last);
int matchScore(int i, int j, bool last);
int missScore(int j, bool last);
};
} // namespace ccls

View File

@ -10,7 +10,7 @@
namespace ccls {
template <typename Node>
std::vector<Location> FlattenHierarchy(const std::optional<Node> &root) {
std::vector<Location> flattenHierarchy(const std::optional<Node> &root) {
if (!root)
return {};
std::vector<Location> ret;

View File

@ -24,7 +24,7 @@ struct CompletionCandidate {
CompletionItem completion_item;
};
std::string ElideLongPath(const std::string &path) {
std::string elideLongPath(const std::string &path) {
if (g_config->completion.include.maxPathSize <= 0 ||
(int)path.size() <= g_config->completion.include.maxPathSize)
return path;
@ -33,7 +33,7 @@ std::string ElideLongPath(const std::string &path) {
return ".." + path.substr(start + 2);
}
size_t TrimCommonPathPrefix(const std::string &result,
size_t trimCommonPathPrefix(const std::string &result,
const std::string &trimmer) {
#ifdef _WIN32
std::string s = result, t = trimmer;
@ -48,21 +48,20 @@ size_t TrimCommonPathPrefix(const std::string &result,
return 0;
}
int TrimPath(Project *project, std::string &path) {
int trimPath(Project *project, std::string &path) {
size_t pos = 0;
int kind = 0;
for (auto &[root, folder] : project->root2folder)
for (auto &[search, search_dir_kind] : folder.search_dir2kind)
if (int t = TrimCommonPathPrefix(path, search); t > pos)
if (int t = trimCommonPathPrefix(path, search); t > pos)
pos = t, kind = search_dir_kind;
path = path.substr(pos);
return kind;
}
CompletionItem BuildCompletionItem(const std::string &path,
int kind) {
CompletionItem buildCompletionItem(const std::string &path, int kind) {
CompletionItem item;
item.label = ElideLongPath(path);
item.label = elideLongPath(path);
item.detail = path; // the include path, used in de-duplicating
item.textEdit.newText = path;
item.insertTextFormat = InsertTextFormat::PlainText;
@ -82,7 +81,7 @@ IncludeComplete::~IncludeComplete() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
void IncludeComplete::Rescan() {
void IncludeComplete::rescan() {
if (is_scanning || LLVM_VERSION_MAJOR >= 8)
return;
@ -104,13 +103,13 @@ void IncludeComplete::Rescan() {
const std::string &search = search_kind.first;
int kind = search_kind.second;
assert(search.back() == '/');
if (match_ && !match_->Matches(search))
if (match_ && !match_->matches(search))
return;
bool include_cpp = search.find("include/c++") != std::string::npos;
std::vector<CompletionCandidate> results;
GetFilesInFolder(search, true /*recursive*/,
false /*add_folder_to_path*/,
getFilesInFolder(
search, true /*recursive*/, false /*add_folder_to_path*/,
[&](const std::string &path) {
bool ok = include_cpp;
for (StringRef suffix :
@ -119,29 +118,27 @@ void IncludeComplete::Rescan() {
ok = true;
if (!ok)
return;
if (match_ && !match_->Matches(search + path))
if (match_ && !match_->matches(search + path))
return;
CompletionCandidate candidate;
candidate.absolute_path = search + path;
candidate.completion_item =
BuildCompletionItem(path, kind);
candidate.completion_item = buildCompletionItem(path, kind);
results.push_back(candidate);
});
std::lock_guard lock(completion_items_mutex);
for (CompletionCandidate &result : results)
InsertCompletionItem(result.absolute_path,
insertCompletionItem(result.absolute_path,
std::move(result.completion_item));
}
}
is_scanning = false;
})
.detach();
}).detach();
}
void IncludeComplete::InsertCompletionItem(const std::string &absolute_path,
void IncludeComplete::insertCompletionItem(const std::string &absolute_path,
CompletionItem &&item) {
if (inserted_paths.try_emplace(item.detail, inserted_paths.size()).second) {
completion_items.push_back(item);
@ -155,28 +152,28 @@ void IncludeComplete::InsertCompletionItem(const std::string &absolute_path,
}
}
void IncludeComplete::AddFile(const std::string &path) {
void IncludeComplete::addFile(const std::string &path) {
bool ok = false;
for (StringRef suffix : g_config->completion.include.suffixWhitelist)
if (StringRef(path).endswith(suffix))
ok = true;
if (!ok)
return;
if (match_ && !match_->Matches(path))
if (match_ && !match_->matches(path))
return;
std::string trimmed_path = path;
int kind = TrimPath(project_, trimmed_path);
CompletionItem item = BuildCompletionItem(trimmed_path, kind);
int kind = trimPath(project_, trimmed_path);
CompletionItem item = buildCompletionItem(trimmed_path, kind);
std::unique_lock<std::mutex> lock(completion_items_mutex, std::defer_lock);
if (is_scanning)
lock.lock();
InsertCompletionItem(path, std::move(item));
insertCompletionItem(path, std::move(item));
}
std::optional<CompletionItem>
IncludeComplete::FindCompletionItemForAbsolutePath(
IncludeComplete::findCompletionItemForAbsolutePath(
const std::string &absolute_path) {
std::lock_guard<std::mutex> lock(completion_items_mutex);

View File

@ -17,17 +17,17 @@ struct IncludeComplete {
~IncludeComplete();
// Starts scanning directories. Clears existing cache.
void Rescan();
void rescan();
// Ensures the one-off file is inside |completion_items|.
void AddFile(const std::string &absolute_path);
void addFile(const std::string &absolute_path);
std::optional<ccls::CompletionItem>
FindCompletionItemForAbsolutePath(const std::string &absolute_path);
findCompletionItemForAbsolutePath(const std::string &absolute_path);
// Insert item to |completion_items|.
// Update |absolute_path_to_completion_item| and |inserted_paths|.
void InsertCompletionItem(const std::string &absolute_path,
void insertCompletionItem(const std::string &absolute_path,
ccls::CompletionItem &&item);
// Guards |completion_items| when |is_scanning| is true.

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@ template <> struct hash<llvm::sys::fs::UniqueID> {
namespace ccls {
using Usr = uint64_t;
// The order matters. In FindSymbolsAtLocation, we want Var/Func ordered in
// The order matters. In findSymbolsAtLocation, we want Var/Func ordered in
// front of others.
enum class Kind : uint8_t { Invalid, File, Type, Func, Var };
REFLECT_UNDERLYING_B(Kind);
@ -76,31 +76,31 @@ struct SymbolRef {
Kind kind;
Role role;
operator SymbolIdx() const { return {usr, kind}; }
std::tuple<Range, Usr, Kind, Role> ToTuple() const {
std::tuple<Range, Usr, Kind, Role> toTuple() const {
return std::make_tuple(range, usr, kind, role);
}
bool operator==(const SymbolRef &o) const { return ToTuple() == o.ToTuple(); }
bool Valid() const { return range.Valid(); }
bool operator==(const SymbolRef &o) const { return toTuple() == o.toTuple(); }
bool valid() const { return range.valid(); }
};
struct ExtentRef : SymbolRef {
Range extent;
std::tuple<Range, Usr, Kind, Role, Range> ToTuple() const {
std::tuple<Range, Usr, Kind, Role, Range> toTuple() const {
return std::make_tuple(range, usr, kind, role, extent);
}
bool operator==(const ExtentRef &o) const { return ToTuple() == o.ToTuple(); }
bool operator==(const ExtentRef &o) const { return toTuple() == o.toTuple(); }
};
struct Ref {
Range range;
Role role;
bool Valid() const { return range.Valid(); }
std::tuple<Range, Role> ToTuple() const {
bool valid() const { return range.valid(); }
std::tuple<Range, Role> toTuple() const {
return std::make_tuple(range, role);
}
bool operator==(const Ref &o) const { return ToTuple() == o.ToTuple(); }
bool operator<(const Ref &o) const { return ToTuple() < o.ToTuple(); }
bool operator==(const Ref &o) const { return toTuple() == o.toTuple(); }
bool operator<(const Ref &o) const { return toTuple() < o.toTuple(); }
};
// Represents an occurrence of a variable/type, |usr,kind| refer to the lexical
@ -118,24 +118,23 @@ struct DeclRef : Use {
Range extent;
};
void Reflect(JsonReader &visitor, SymbolRef &value);
void Reflect(JsonReader &visitor, Use &value);
void Reflect(JsonReader &visitor, DeclRef &value);
void Reflect(JsonWriter &visitor, SymbolRef &value);
void Reflect(JsonWriter &visitor, Use &value);
void Reflect(JsonWriter &visitor, DeclRef &value);
void Reflect(BinaryReader &visitor, SymbolRef &value);
void Reflect(BinaryReader &visitor, Use &value);
void Reflect(BinaryReader &visitor, DeclRef &value);
void Reflect(BinaryWriter &visitor, SymbolRef &value);
void Reflect(BinaryWriter &visitor, Use &value);
void Reflect(BinaryWriter &visitor, DeclRef &value);
void reflect(JsonReader &visitor, SymbolRef &value);
void reflect(JsonReader &visitor, Use &value);
void reflect(JsonReader &visitor, DeclRef &value);
void reflect(JsonWriter &visitor, SymbolRef &value);
void reflect(JsonWriter &visitor, Use &value);
void reflect(JsonWriter &visitor, DeclRef &value);
void reflect(BinaryReader &visitor, SymbolRef &value);
void reflect(BinaryReader &visitor, Use &value);
void reflect(BinaryReader &visitor, DeclRef &value);
void reflect(BinaryWriter &visitor, SymbolRef &value);
void reflect(BinaryWriter &visitor, Use &value);
void reflect(BinaryWriter &visitor, DeclRef &value);
template <typename T>
using VectorAdapter = std::vector<T, std::allocator<T>>;
template <typename T> using VectorAdapter = std::vector<T, std::allocator<T>>;
template <typename D> struct NameMixin {
std::string_view Name(bool qualified) const {
std::string_view name(bool qualified) const {
auto self = static_cast<const D *>(this);
return qualified
? std::string_view(self->detailed_name + self->qual_name_offset,
@ -320,11 +319,11 @@ struct IndexFile {
IndexFile(const std::string &path, const std::string &contents,
bool no_linkage);
IndexFunc &ToFunc(Usr usr);
IndexType &ToType(Usr usr);
IndexVar &ToVar(Usr usr);
IndexFunc &toFunc(Usr usr);
IndexType &toType(Usr usr);
IndexVar &toVar(Usr usr);
std::string ToString();
std::string toString();
};
struct SemaManager;
@ -332,9 +331,9 @@ struct WorkingFiles;
struct VFS;
namespace idx {
void Init();
void init();
std::vector<std::unique_ptr<IndexFile>>
Index(SemaManager *complete, WorkingFiles *wfiles, VFS *vfs,
index(SemaManager *complete, WorkingFiles *wfiles, VFS *vfs,
const std::string &opt_wdir, const std::string &file,
const std::vector<const char *> &args,
const std::vector<std::pair<std::string, std::string>> &remapped,

View File

@ -30,9 +30,9 @@ Message::Message(Verbosity verbosity, const char *file, int line)
snprintf(buf, sizeof buf, "%02d:%02d:%02d ", t.tm_hour, t.tm_min, t.tm_sec);
stream_ << buf;
{
SmallString<32> Name;
get_thread_name(Name);
stream_ << std::left << std::setw(13) << Name.c_str();
SmallString<32> name;
get_thread_name(name);
stream_ << std::left << std::setw(13) << name.c_str();
}
{
const char *p = strrchr(file, '/');

View File

@ -3,8 +3,8 @@
#pragma once
#include <stdio.h>
#include <sstream>
#include <stdio.h>
namespace ccls::log {
extern FILE *file;
@ -28,7 +28,7 @@ struct Message {
Message(Verbosity verbosity, const char *file, int line);
~Message();
};
}
} // namespace ccls::log
#define LOG_IF(v, cond) \
!(cond) ? void(0) \

View File

@ -11,7 +11,7 @@
#include <stdio.h>
namespace ccls {
void Reflect(JsonReader &vis, RequestId &v) {
void reflect(JsonReader &vis, RequestId &v) {
if (vis.m->IsInt64()) {
v.type = RequestId::kInt;
v.value = std::to_string(int(vis.m->GetInt64()));
@ -27,27 +27,27 @@ void Reflect(JsonReader &vis, RequestId &v) {
}
}
void Reflect(JsonWriter &visitor, RequestId &value) {
void reflect(JsonWriter &visitor, RequestId &value) {
switch (value.type) {
case RequestId::kNone:
visitor.Null();
visitor.null_();
break;
case RequestId::kInt:
visitor.Int(atoll(value.value.c_str()));
visitor.int_(atoll(value.value.c_str()));
break;
case RequestId::kString:
visitor.String(value.value.c_str(), value.value.size());
visitor.string(value.value.c_str(), value.value.size());
break;
}
}
DocumentUri DocumentUri::FromPath(const std::string &path) {
DocumentUri DocumentUri::fromPath(const std::string &path) {
DocumentUri result;
result.SetPath(path);
result.setPath(path);
return result;
}
void DocumentUri::SetPath(const std::string &path) {
void DocumentUri::setPath(const std::string &path) {
// file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests
raw_uri = path;
@ -88,7 +88,7 @@ void DocumentUri::SetPath(const std::string &path) {
raw_uri = std::move(t);
}
std::string DocumentUri::GetPath() const {
std::string DocumentUri::getPath() const {
if (raw_uri.compare(0, 7, "file://")) {
LOG_S(WARNING)
<< "Received potentially bad URI (not starting with file://): "
@ -119,11 +119,11 @@ std::string DocumentUri::GetPath() const {
}
#endif
if (g_config)
NormalizeFolder(ret);
normalizeFolder(ret);
return ret;
}
std::string Position::ToString() const {
std::string Position::toString() const {
return std::to_string(line) + ":" + std::to_string(character);
}
} // namespace ccls

View File

@ -22,10 +22,10 @@ struct RequestId {
std::string value;
bool Valid() const { return type != kNone; }
bool valid() const { return type != kNone; }
};
void Reflect(JsonReader &visitor, RequestId &value);
void Reflect(JsonWriter &visitor, RequestId &value);
void reflect(JsonReader &visitor, RequestId &value);
void reflect(JsonWriter &visitor, RequestId &value);
struct InMessage {
RequestId id;
@ -61,13 +61,13 @@ constexpr char ccls_xref[] = "ccls.xref";
constexpr char window_showMessage[] = "window/showMessage";
struct DocumentUri {
static DocumentUri FromPath(const std::string &path);
static DocumentUri fromPath(const std::string &path);
bool operator==(const DocumentUri &o) const { return raw_uri == o.raw_uri; }
bool operator<(const DocumentUri &o) const { return raw_uri < o.raw_uri; }
void SetPath(const std::string &path);
std::string GetPath() const;
void setPath(const std::string &path);
std::string getPath() const;
std::string raw_uri;
};
@ -84,7 +84,7 @@ struct Position {
bool operator<=(const Position &o) const {
return line != o.line ? line < o.line : character <= o.character;
}
std::string ToString() const;
std::string toString() const;
};
struct lsRange {
@ -96,10 +96,10 @@ struct lsRange {
bool operator<(const lsRange &o) const {
return !(start == o.start) ? start < o.start : end < o.end;
}
bool Includes(const lsRange &o) const {
bool includes(const lsRange &o) const {
return start <= o.start && o.end <= end;
}
bool Intersects(const lsRange &o) const {
bool intersects(const lsRange &o) const {
return start < o.end && o.start < end;
}
};

View File

@ -52,15 +52,15 @@ opt<std::string> opt_log_file("log-file", desc("stderr or log file"),
opt<bool> opt_log_file_append("log-file-append", desc("append to log file"),
cat(C));
void CloseLog() { fclose(ccls::log::file); }
void closeLog() { fclose(ccls::log::file); }
} // namespace
int main(int argc, char **argv) {
TraceMe();
traceMe();
sys::PrintStackTraceOnErrorSignal(argv[0]);
cl::SetVersionPrinter([](raw_ostream &OS) {
OS << clang::getClangToolFullVersion("ccls version " CCLS_VERSION "\nclang")
cl::SetVersionPrinter([](raw_ostream &os) {
os << clang::getClangToolFullVersion("ccls version " CCLS_VERSION "\nclang")
<< "\n";
});
@ -76,7 +76,7 @@ int main(int argc, char **argv) {
}
ccls::log::verbosity = ccls::log::Verbosity(opt_verbose.getValue());
pipeline::Init();
pipeline::init();
const char *env = getenv("CCLS_CRASH_RECOVERY");
if (!env || strcmp(env, "0") != 0)
CrashRecoveryContext::Enable();
@ -93,12 +93,13 @@ int main(int argc, char **argv) {
return 2;
}
setbuf(ccls::log::file, NULL);
atexit(CloseLog);
atexit(closeLog);
}
if (opt_test_index != "!") {
language_server = false;
if (!ccls::RunIndexTests(opt_test_index, sys::Process::StandardInIsUserInput()))
if (!ccls::runIndexTests(opt_test_index,
sys::Process::StandardInIsUserInput()))
return 1;
}
@ -118,10 +119,10 @@ int main(int argc, char **argv) {
JsonReader json_reader{&reader};
try {
Config config;
Reflect(json_reader, config);
reflect(json_reader, config);
} catch (std::invalid_argument &e) {
fprintf(stderr, "Failed to parse --init %s, expected %s\n",
static_cast<JsonReader &>(json_reader).GetPath().c_str(),
static_cast<JsonReader &>(json_reader).getPath().c_str(),
e.what());
return 1;
}
@ -131,18 +132,18 @@ int main(int argc, char **argv) {
sys::ChangeStdinToBinary();
sys::ChangeStdoutToBinary();
if (opt_index.size()) {
SmallString<256> Root(opt_index);
sys::fs::make_absolute(Root);
pipeline::Standalone(Root.str());
SmallString<256> root(opt_index);
sys::fs::make_absolute(root);
pipeline::standalone(root.str());
} else {
// The thread that reads from stdin and dispatchs commands to the main
// thread.
pipeline::LaunchStdin();
pipeline::launchStdin();
// The thread that writes responses from the main thread to stdout.
pipeline::LaunchStdout();
pipeline::launchStdout();
// Main thread which also spawns indexer threads upon the "initialize"
// request.
pipeline::MainLoop();
pipeline::mainLoop();
}
}

View File

@ -21,7 +21,7 @@ MAKE_HASHABLE(ccls::SymbolIdx, t.usr, t.kind);
namespace ccls {
REFLECT_STRUCT(CodeActionParam::Context, diagnostics);
REFLECT_STRUCT(CodeActionParam, textDocument, range, context);
void Reflect(JsonReader &, EmptyParam &) {}
void reflect(JsonReader &, EmptyParam &) {}
REFLECT_STRUCT(TextDocumentParam, textDocument);
REFLECT_STRUCT(DidOpenTextDocumentParam, textDocument);
REFLECT_STRUCT(TextDocumentContentChangeEvent, range, rangeLength, text);
@ -97,11 +97,11 @@ struct ScanLineEvent {
};
} // namespace
void ReplyOnce::NotOpened(std::string_view path) {
Error(ErrorCode::InvalidRequest, std::string(path) + " is not opened");
void ReplyOnce::notOpened(std::string_view path) {
error(ErrorCode::InvalidRequest, std::string(path) + " is not opened");
}
void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
void ReplyOnce::replyLocationLink(std::vector<LocationLink> &result) {
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
if (result.size() > g_config->xref.maxNum)
@ -116,7 +116,7 @@ void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
}
}
void MessageHandler::Bind(const char *method,
void MessageHandler::bind(const char *method,
void (MessageHandler::*handler)(JsonReader &)) {
method2notification[method] = [this, handler](JsonReader &reader) {
(this->*handler)(reader);
@ -124,16 +124,16 @@ void MessageHandler::Bind(const char *method,
}
template <typename Param>
void MessageHandler::Bind(const char *method,
void MessageHandler::bind(const char *method,
void (MessageHandler::*handler)(Param &)) {
method2notification[method] = [this, handler](JsonReader &reader) {
Param param{};
Reflect(reader, param);
reflect(reader, param);
(this->*handler)(param);
};
}
void MessageHandler::Bind(const char *method,
void MessageHandler::bind(const char *method,
void (MessageHandler::*handler)(JsonReader &,
ReplyOnce &)) {
method2request[method] = [this, handler](JsonReader &reader,
@ -143,83 +143,84 @@ void MessageHandler::Bind(const char *method,
}
template <typename Param>
void MessageHandler::Bind(const char *method,
void MessageHandler::bind(const char *method,
void (MessageHandler::*handler)(Param &,
ReplyOnce &)) {
method2request[method] = [this, handler](JsonReader &reader,
ReplyOnce &reply) {
Param param{};
Reflect(reader, param);
reflect(reader, param);
(this->*handler)(param, reply);
};
}
MessageHandler::MessageHandler() {
// clang-format off
Bind("$ccls/call", &MessageHandler::ccls_call);
Bind("$ccls/fileInfo", &MessageHandler::ccls_fileInfo);
Bind("$ccls/info", &MessageHandler::ccls_info);
Bind("$ccls/inheritance", &MessageHandler::ccls_inheritance);
Bind("$ccls/member", &MessageHandler::ccls_member);
Bind("$ccls/navigate", &MessageHandler::ccls_navigate);
Bind("$ccls/reload", &MessageHandler::ccls_reload);
Bind("$ccls/vars", &MessageHandler::ccls_vars);
Bind("exit", &MessageHandler::exit);
Bind("initialize", &MessageHandler::initialize);
Bind("initialized", &MessageHandler::initialized);
Bind("shutdown", &MessageHandler::shutdown);
Bind("textDocument/codeAction", &MessageHandler::textDocument_codeAction);
Bind("textDocument/codeLens", &MessageHandler::textDocument_codeLens);
Bind("textDocument/completion", &MessageHandler::textDocument_completion);
Bind("textDocument/declaration", &MessageHandler::textDocument_declaration);
Bind("textDocument/definition", &MessageHandler::textDocument_definition);
Bind("textDocument/didChange", &MessageHandler::textDocument_didChange);
Bind("textDocument/didClose", &MessageHandler::textDocument_didClose);
Bind("textDocument/didOpen", &MessageHandler::textDocument_didOpen);
Bind("textDocument/didSave", &MessageHandler::textDocument_didSave);
Bind("textDocument/documentHighlight", &MessageHandler::textDocument_documentHighlight);
Bind("textDocument/documentLink", &MessageHandler::textDocument_documentLink);
Bind("textDocument/documentSymbol", &MessageHandler::textDocument_documentSymbol);
Bind("textDocument/foldingRange", &MessageHandler::textDocument_foldingRange);
Bind("textDocument/formatting", &MessageHandler::textDocument_formatting);
Bind("textDocument/hover", &MessageHandler::textDocument_hover);
Bind("textDocument/implementation", &MessageHandler::textDocument_implementation);
Bind("textDocument/onTypeFormatting", &MessageHandler::textDocument_onTypeFormatting);
Bind("textDocument/rangeFormatting", &MessageHandler::textDocument_rangeFormatting);
Bind("textDocument/references", &MessageHandler::textDocument_references);
Bind("textDocument/rename", &MessageHandler::textDocument_rename);
Bind("textDocument/signatureHelp", &MessageHandler::textDocument_signatureHelp);
Bind("textDocument/typeDefinition", &MessageHandler::textDocument_typeDefinition);
Bind("workspace/didChangeConfiguration", &MessageHandler::workspace_didChangeConfiguration);
Bind("workspace/didChangeWatchedFiles", &MessageHandler::workspace_didChangeWatchedFiles);
Bind("workspace/didChangeWorkspaceFolders", &MessageHandler::workspace_didChangeWorkspaceFolders);
Bind("workspace/executeCommand", &MessageHandler::workspace_executeCommand);
Bind("workspace/symbol", &MessageHandler::workspace_symbol);
bind("$ccls/call", &MessageHandler::ccls_call);
bind("$ccls/fileInfo", &MessageHandler::ccls_fileInfo);
bind("$ccls/info", &MessageHandler::ccls_info);
bind("$ccls/inheritance", &MessageHandler::ccls_inheritance);
bind("$ccls/member", &MessageHandler::ccls_member);
bind("$ccls/navigate", &MessageHandler::ccls_navigate);
bind("$ccls/reload", &MessageHandler::ccls_reload);
bind("$ccls/vars", &MessageHandler::ccls_vars);
bind("exit", &MessageHandler::exit);
bind("initialize", &MessageHandler::initialize);
bind("initialized", &MessageHandler::initialized);
bind("shutdown", &MessageHandler::shutdown);
bind("textDocument/codeAction", &MessageHandler::textDocument_codeAction);
bind("textDocument/codeLens", &MessageHandler::textDocument_codeLens);
bind("textDocument/completion", &MessageHandler::textDocument_completion);
bind("textDocument/declaration", &MessageHandler::textDocument_declaration);
bind("textDocument/definition", &MessageHandler::textDocument_definition);
bind("textDocument/didChange", &MessageHandler::textDocument_didChange);
bind("textDocument/didClose", &MessageHandler::textDocument_didClose);
bind("textDocument/didOpen", &MessageHandler::textDocument_didOpen);
bind("textDocument/didSave", &MessageHandler::textDocument_didSave);
bind("textDocument/documentHighlight", &MessageHandler::textDocument_documentHighlight);
bind("textDocument/documentLink", &MessageHandler::textDocument_documentLink);
bind("textDocument/documentSymbol", &MessageHandler::textDocument_documentSymbol);
bind("textDocument/foldingRange", &MessageHandler::textDocument_foldingRange);
bind("textDocument/formatting", &MessageHandler::textDocument_formatting);
bind("textDocument/hover", &MessageHandler::textDocument_hover);
bind("textDocument/implementation", &MessageHandler::textDocument_implementation);
bind("textDocument/onTypeFormatting", &MessageHandler::textDocument_onTypeFormatting);
bind("textDocument/rangeFormatting", &MessageHandler::textDocument_rangeFormatting);
bind("textDocument/references", &MessageHandler::textDocument_references);
bind("textDocument/rename", &MessageHandler::textDocument_rename);
bind("textDocument/signatureHelp", &MessageHandler::textDocument_signatureHelp);
bind("textDocument/typeDefinition", &MessageHandler::textDocument_typeDefinition);
bind("workspace/didChangeConfiguration", &MessageHandler::workspace_didChangeConfiguration);
bind("workspace/didChangeWatchedFiles", &MessageHandler::workspace_didChangeWatchedFiles);
bind("workspace/didChangeWorkspaceFolders", &MessageHandler::workspace_didChangeWorkspaceFolders);
bind("workspace/executeCommand", &MessageHandler::workspace_executeCommand);
bind("workspace/symbol", &MessageHandler::workspace_symbol);
// clang-format on
}
void MessageHandler::Run(InMessage &msg) {
void MessageHandler::run(InMessage &msg) {
rapidjson::Document &doc = *msg.document;
rapidjson::Value null;
auto it = doc.FindMember("params");
JsonReader reader(it != doc.MemberEnd() ? &it->value : &null);
if (msg.id.Valid()) {
if (msg.id.valid()) {
ReplyOnce reply{*this, msg.id};
auto it = method2request.find(msg.method);
if (it != method2request.end()) {
try {
it->second(reader, reply);
} catch (std::invalid_argument &ex) {
reply.Error(ErrorCode::InvalidParams,
reply.error(ErrorCode::InvalidParams,
"invalid params of " + msg.method + ": expected " +
ex.what() + " for " + reader.GetPath());
ex.what() + " for " + reader.getPath());
} catch (NotIndexed &) {
throw;
} catch (...) {
reply.Error(ErrorCode::InternalError, "failed to process " + msg.method);
reply.error(ErrorCode::InternalError,
"failed to process " + msg.method);
}
} else {
reply.Error(ErrorCode::MethodNotFound, "unknown request " + msg.method);
reply.error(ErrorCode::MethodNotFound, "unknown request " + msg.method);
}
} else {
auto it = method2notification.find(msg.method);
@ -229,15 +230,14 @@ void MessageHandler::Run(InMessage &msg) {
} catch (...) {
ShowMessageParam param{MessageType::Error,
std::string("failed to process ") + msg.method};
pipeline::Notify(window_showMessage, param);
pipeline::notify(window_showMessage, param);
}
}
}
QueryFile *MessageHandler::FindFile(const std::string &path,
int *out_file_id) {
QueryFile *MessageHandler::findFile(const std::string &path, int *out_file_id) {
QueryFile *ret = nullptr;
auto it = db->name2file_id.find(LowerPathIfInsensitive(path));
auto it = db->name2file_id.find(lowerPathIfInsensitive(path));
if (it != db->name2file_id.end()) {
QueryFile &file = db->files[it->second];
if (file.def) {
@ -253,44 +253,45 @@ QueryFile *MessageHandler::FindFile(const std::string &path,
}
std::pair<QueryFile *, WorkingFile *>
MessageHandler::FindOrFail(const std::string &path, ReplyOnce &reply,
MessageHandler::findOrFail(const std::string &path, ReplyOnce &reply,
int *out_file_id) {
WorkingFile *wf = wfiles->GetFile(path);
WorkingFile *wf = wfiles->getFile(path);
if (!wf) {
reply.NotOpened(path);
reply.notOpened(path);
return {nullptr, nullptr};
}
QueryFile *file = FindFile(path, out_file_id);
QueryFile *file = findFile(path, out_file_id);
if (!file) {
if (!overdue)
throw NotIndexed{path};
reply.Error(ErrorCode::InvalidRequest, "not indexed");
reply.error(ErrorCode::InvalidRequest, "not indexed");
return {nullptr, nullptr};
}
return {file, wf};
}
void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file) {
void emitSkippedRanges(WorkingFile *wfile, QueryFile &file) {
CclsSetSkippedRanges params;
params.uri = DocumentUri::FromPath(wfile->filename);
params.uri = DocumentUri::fromPath(wfile->filename);
for (Range skipped : file.def->skipped_ranges)
if (auto ls_skipped = GetLsRange(wfile, skipped))
if (auto ls_skipped = getLsRange(wfile, skipped))
params.skippedRanges.push_back(*ls_skipped);
pipeline::Notify("$ccls/publishSkippedRanges", params);
pipeline::notify("$ccls/publishSkippedRanges", params);
}
void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
void emitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
static GroupMatch match(g_config->highlight.whitelist,
g_config->highlight.blacklist);
assert(file.def);
if (wfile->buffer_content.size() > g_config->highlight.largeFileSize ||
!match.Matches(file.def->path))
!match.matches(file.def->path))
return;
// Group symbols together.
std::unordered_map<SymbolIdx, CclsSemanticHighlightSymbol> grouped_symbols;
for (auto [sym, refcnt] : file.symbol2refcnt) {
if (refcnt <= 0) continue;
if (refcnt <= 0)
continue;
std::string_view detailed_name;
SymbolKind parent_kind = SymbolKind::Unknown;
SymbolKind kind = SymbolKind::Unknown;
@ -301,12 +302,12 @@ void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
case Kind::Func: {
idx = db->func_usr[sym.usr];
const QueryFunc &func = db->funcs[idx];
const QueryFunc::Def *def = func.AnyDef();
const QueryFunc::Def *def = func.anyDef();
if (!def)
continue; // applies to for loop
// Don't highlight overloadable operators or implicit lambda ->
// std::function constructor.
std::string_view short_name = def->Name(false);
std::string_view short_name = def->name(false);
if (short_name.compare(0, 8, "operator") == 0)
continue; // applies to for loop
kind = def->kind;
@ -363,7 +364,7 @@ void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
continue; // applies to for loop
}
if (std::optional<lsRange> loc = GetLsRange(wfile, sym.range)) {
if (std::optional<lsRange> loc = getLsRange(wfile, sym.range)) {
auto it = grouped_symbols.find(sym);
if (it != grouped_symbols.end()) {
it->second.lsRanges.push_back(*loc);
@ -419,7 +420,7 @@ void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
}
CclsSemanticHighlight params;
params.uri = DocumentUri::FromPath(wfile->filename);
params.uri = DocumentUri::fromPath(wfile->filename);
// Transform lsRange into pair<int, int> (offset pairs)
if (!g_config->highlight.lsRanges) {
std::vector<std::pair<lsRange, CclsSemanticHighlightSymbol *>> scratch;
@ -465,6 +466,6 @@ void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
for (auto &entry : grouped_symbols)
if (entry.second.ranges.size() || entry.second.lsRanges.size())
params.symbols.push_back(std::move(entry.second));
pipeline::Notify("$ccls/publishSemanticHighlight", params);
pipeline::notify("$ccls/publishSemanticHighlight", params);
}
} // namespace ccls

View File

@ -20,9 +20,9 @@ struct WorkingFile;
struct WorkingFiles;
namespace pipeline {
void Reply(RequestId id, const std::function<void(JsonWriter &)> &fn);
void ReplyError(RequestId id, const std::function<void(JsonWriter &)> &fn);
}
void reply(RequestId id, const std::function<void(JsonWriter &)> &fn);
void replyError(RequestId id, const std::function<void(JsonWriter &)> &fn);
} // namespace pipeline
struct CodeActionParam {
TextDocumentIdentifier textDocument;
@ -97,10 +97,7 @@ enum class CompletionItemKind {
Operator = 24,
TypeParameter = 25,
};
enum class InsertTextFormat {
PlainText = 1,
Snippet = 2
};
enum class InsertTextFormat { PlainText = 1, Snippet = 2 };
struct CompletionItem {
std::string label;
CompletionItemKind kind = CompletionItemKind::Text;
@ -165,22 +162,22 @@ struct WorkspaceSymbolParam {
};
REFLECT_STRUCT(WorkspaceFolder, uri, name);
inline void Reflect(JsonReader &vis, DocumentUri &v) {
Reflect(vis, v.raw_uri);
inline void reflect(JsonReader &vis, DocumentUri &v) {
reflect(vis, v.raw_uri);
}
inline void Reflect(JsonWriter &vis, DocumentUri &v) {
Reflect(vis, v.raw_uri);
inline void reflect(JsonWriter &vis, DocumentUri &v) {
reflect(vis, v.raw_uri);
}
inline void Reflect(JsonReader &vis, VersionedTextDocumentIdentifier &v) {
inline void reflect(JsonReader &vis, VersionedTextDocumentIdentifier &v) {
REFLECT_MEMBER(uri);
REFLECT_MEMBER(version);
}
inline void Reflect(JsonWriter &vis, VersionedTextDocumentIdentifier &v) {
vis.StartObject();
inline void reflect(JsonWriter &vis, VersionedTextDocumentIdentifier &v) {
vis.startObject();
REFLECT_MEMBER(uri);
vis.Key("version");
Reflect(vis, v.version);
vis.EndObject();
vis.key("version");
reflect(vis, v.version);
vis.endObject();
}
REFLECT_UNDERLYING(ErrorCode);
@ -194,7 +191,8 @@ REFLECT_STRUCT(TextDocumentIdentifier, uri);
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
REFLECT_STRUCT(TextEdit, range, newText);
REFLECT_STRUCT(DiagnosticRelatedInformation, location, message);
REFLECT_STRUCT(Diagnostic, range, severity, code, source, message, relatedInformation);
REFLECT_STRUCT(Diagnostic, range, severity, code, source, message,
relatedInformation);
REFLECT_STRUCT(ShowMessageParam, type, message);
REFLECT_UNDERLYING_B(LanguageId);
@ -207,16 +205,16 @@ struct ReplyOnce {
MessageHandler &handler;
RequestId id;
template <typename Res> void operator()(Res &&result) const {
if (id.Valid())
pipeline::Reply(id, [&](JsonWriter &w) { Reflect(w, result); });
if (id.valid())
pipeline::reply(id, [&](JsonWriter &w) { reflect(w, result); });
}
void Error(ErrorCode code, std::string message) const {
void error(ErrorCode code, std::string message) const {
ResponseError err{code, std::move(message)};
if (id.Valid())
pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
if (id.valid())
pipeline::replyError(id, [&](JsonWriter &w) { reflect(w, err); });
}
void NotOpened(std::string_view path);
void ReplyLocationLink(std::vector<LocationLink> &result);
void notOpened(std::string_view path);
void replyLocationLink(std::vector<LocationLink> &result);
};
struct MessageHandler {
@ -233,20 +231,20 @@ struct MessageHandler {
bool overdue = false;
MessageHandler();
void Run(InMessage &msg);
QueryFile *FindFile(const std::string &path, int *out_file_id = nullptr);
std::pair<QueryFile *, WorkingFile *> FindOrFail(const std::string &path,
void run(InMessage &msg);
QueryFile *findFile(const std::string &path, int *out_file_id = nullptr);
std::pair<QueryFile *, WorkingFile *> findOrFail(const std::string &path,
ReplyOnce &reply,
int *out_file_id = nullptr);
private:
void Bind(const char *method, void (MessageHandler::*handler)(JsonReader &));
void bind(const char *method, void (MessageHandler::*handler)(JsonReader &));
template <typename Param>
void Bind(const char *method, void (MessageHandler::*handler)(Param &));
void Bind(const char *method,
void bind(const char *method, void (MessageHandler::*handler)(Param &));
void bind(const char *method,
void (MessageHandler::*handler)(JsonReader &, ReplyOnce &));
template <typename Param>
void Bind(const char *method,
void bind(const char *method,
void (MessageHandler::*handler)(Param &, ReplyOnce &));
void ccls_call(JsonReader &, ReplyOnce &);
@ -292,7 +290,7 @@ private:
void workspace_symbol(WorkspaceSymbolParam &, ReplyOnce &);
};
void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file);
void emitSkippedRanges(WorkingFile *wfile, QueryFile &file);
void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file);
void emitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file);
} // namespace ccls

View File

@ -60,10 +60,10 @@ struct Out_cclsCall {
REFLECT_STRUCT(Out_cclsCall, id, name, location, callType, numChildren,
children);
bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
bool expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
CallType call_type, bool qualified, int levels) {
const QueryFunc &func = m->db->Func(entry->usr);
const QueryFunc::Def *def = func.AnyDef();
const QueryFunc &func = m->db->getFunc(entry->usr);
const QueryFunc::Def *def = func.anyDef();
entry->numChildren = 0;
if (!def)
return false;
@ -73,17 +73,17 @@ bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
Out_cclsCall entry1;
entry1.id = std::to_string(sym.usr);
entry1.usr = sym.usr;
if (auto loc = GetLsLocation(m->db, m->wfiles,
if (auto loc = getLsLocation(m->db, m->wfiles,
Use{{sym.range, sym.role}, file_id}))
entry1.location = *loc;
entry1.callType = call_type1;
if (Expand(m, &entry1, callee, call_type, qualified, levels - 1))
if (expand(m, &entry1, callee, call_type, qualified, levels - 1))
entry->children.push_back(std::move(entry1));
}
};
auto handle_uses = [&](const QueryFunc &func, CallType call_type) {
if (callee) {
if (const auto *def = func.AnyDef())
if (const auto *def = func.anyDef())
for (SymbolRef sym : def->callees)
if (sym.kind == Kind::Func)
handle(sym, def->file_id, call_type);
@ -92,7 +92,7 @@ bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
const QueryFile &file1 = m->db->files[use.file_id];
Maybe<ExtentRef> best;
for (auto [sym, refcnt] : file1.symbol2refcnt)
if (refcnt > 0 && sym.extent.Valid() && sym.kind == Kind::Func &&
if (refcnt > 0 && sym.extent.valid() && sym.kind == Kind::Func &&
sym.extent.start <= use.range.start &&
use.range.end <= sym.extent.end &&
(!best || best->extent.start < sym.extent.start))
@ -106,7 +106,7 @@ bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
std::unordered_set<Usr> seen;
seen.insert(func.usr);
std::vector<const QueryFunc *> stack;
entry->name = def->Name(qualified);
entry->name = def->name(qualified);
handle_uses(func, CallType::Direct);
// Callers/callees of base functions.
@ -115,8 +115,8 @@ bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
while (stack.size()) {
const QueryFunc &func1 = *stack.back();
stack.pop_back();
if (auto *def1 = func1.AnyDef()) {
EachDefinedFunc(m->db, def1->bases, [&](QueryFunc &func2) {
if (auto *def1 = func1.anyDef()) {
eachDefinedFunc(m->db, def1->bases, [&](QueryFunc &func2) {
if (!seen.count(func2.usr)) {
seen.insert(func2.usr);
stack.push_back(&func2);
@ -133,7 +133,7 @@ bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
while (stack.size()) {
const QueryFunc &func1 = *stack.back();
stack.pop_back();
EachDefinedFunc(m->db, func1.derived, [&](QueryFunc &func2) {
eachDefinedFunc(m->db, func1.derived, [&](QueryFunc &func2) {
if (!seen.count(func2.usr)) {
seen.insert(func2.usr);
stack.push_back(&func2);
@ -150,10 +150,10 @@ bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee,
return true;
}
std::optional<Out_cclsCall> BuildInitial(MessageHandler *m, Usr root_usr,
std::optional<Out_cclsCall> buildInitial(MessageHandler *m, Usr root_usr,
bool callee, CallType call_type,
bool qualified, int levels) {
const auto *def = m->db->Func(root_usr).AnyDef();
const auto *def = m->db->getFunc(root_usr).anyDef();
if (!def)
return {};
@ -162,17 +162,17 @@ std::optional<Out_cclsCall> BuildInitial(MessageHandler *m, Usr root_usr,
entry.usr = root_usr;
entry.callType = CallType::Direct;
if (def->spell) {
if (auto loc = GetLsLocation(m->db, m->wfiles, *def->spell))
if (auto loc = getLsLocation(m->db, m->wfiles, *def->spell))
entry.location = *loc;
}
Expand(m, &entry, callee, call_type, qualified, levels);
expand(m, &entry, callee, call_type, qualified, levels);
return entry;
}
} // namespace
void MessageHandler::ccls_call(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
reflect(reader, param);
std::optional<Out_cclsCall> result;
if (param.id.size()) {
try {
@ -184,16 +184,16 @@ void MessageHandler::ccls_call(JsonReader &reader, ReplyOnce &reply) {
result->id = std::to_string(param.usr);
result->usr = param.usr;
result->callType = CallType::Direct;
if (db->HasFunc(param.usr))
Expand(this, &*result, param.callee, param.callType, param.qualified,
if (db->hasFunc(param.usr))
expand(this, &*result, param.callee, param.callType, param.qualified,
param.levels);
} else {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
if (sym.kind == Kind::Func) {
result = BuildInitial(this, sym.usr, param.callee, param.callType,
result = buildInitial(this, sym.usr, param.callee, param.callType,
param.qualified, param.levels);
break;
}
@ -203,6 +203,6 @@ void MessageHandler::ccls_call(JsonReader &reader, ReplyOnce &reply) {
if (param.hierarchy)
reply(result);
else
reply(FlattenHierarchy(result));
reply(flattenHierarchy(result));
}
} // namespace ccls

View File

@ -47,12 +47,13 @@ struct FileInfoParam : TextDocumentParam {
bool includes = false;
bool skipped_ranges = false;
};
REFLECT_STRUCT(FileInfoParam, textDocument, dependencies, includes, skipped_ranges);
REFLECT_STRUCT(FileInfoParam, textDocument, dependencies, includes,
skipped_ranges);
void MessageHandler::ccls_fileInfo(JsonReader &reader, ReplyOnce &reply) {
FileInfoParam param;
Reflect(reader, param);
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
reflect(reader, param);
QueryFile *file = findFile(param.textDocument.uri.getPath());
if (!file)
return;

View File

@ -42,20 +42,20 @@ struct Out_cclsInheritance {
REFLECT_STRUCT(Out_cclsInheritance, id, kind, name, location, numChildren,
children);
bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool qualified, int levels);
template <typename Q>
bool ExpandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool expandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool qualified, int levels, Q &entity) {
const auto *def = entity.AnyDef();
const auto *def = entity.anyDef();
if (def) {
entry->name = def->Name(qualified);
entry->name = def->name(qualified);
if (def->spell) {
if (auto loc = GetLsLocation(m->db, m->wfiles, *def->spell))
if (auto loc = getLsLocation(m->db, m->wfiles, *def->spell))
entry->location = *loc;
} else if (entity.declarations.size()) {
if (auto loc = GetLsLocation(m->db, m->wfiles, entity.declarations[0]))
if (auto loc = getLsLocation(m->db, m->wfiles, entity.declarations[0]))
entry->location = *loc;
}
} else if (!derived) {
@ -72,7 +72,7 @@ bool ExpandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
entry1.id = std::to_string(usr);
entry1.usr = usr;
entry1.kind = entry->kind;
if (Expand(m, &entry1, derived, qualified, levels - 1))
if (expand(m, &entry1, derived, qualified, levels - 1))
entry->children.push_back(std::move(entry1));
}
entry->numChildren = int(entry->children.size());
@ -87,7 +87,7 @@ bool ExpandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
entry1.id = std::to_string(usr);
entry1.usr = usr;
entry1.kind = entry->kind;
if (Expand(m, &entry1, derived, qualified, levels - 1))
if (expand(m, &entry1, derived, qualified, levels - 1))
entry->children.push_back(std::move(entry1));
}
entry->numChildren = int(entry->children.size());
@ -97,27 +97,28 @@ bool ExpandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
return true;
}
bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool qualified, int levels) {
if (entry->kind == Kind::Func)
return ExpandHelper(m, entry, derived, qualified, levels,
m->db->Func(entry->usr));
return expandHelper(m, entry, derived, qualified, levels,
m->db->getFunc(entry->usr));
else
return ExpandHelper(m, entry, derived, qualified, levels,
m->db->Type(entry->usr));
return expandHelper(m, entry, derived, qualified, levels,
m->db->getType(entry->usr));
}
std::optional<Out_cclsInheritance> BuildInitial(MessageHandler *m, SymbolRef sym, bool derived,
std::optional<Out_cclsInheritance> buildInitial(MessageHandler *m,
SymbolRef sym, bool derived,
bool qualified, int levels) {
Out_cclsInheritance entry;
entry.id = std::to_string(sym.usr);
entry.usr = sym.usr;
entry.kind = sym.kind;
Expand(m, &entry, derived, qualified, levels);
expand(m, &entry, derived, qualified, levels);
return entry;
}
void Inheritance(MessageHandler *m, Param &param, ReplyOnce &reply) {
void inheritance(MessageHandler *m, Param &param, ReplyOnce &reply) {
std::optional<Out_cclsInheritance> result;
if (param.id.size()) {
try {
@ -129,19 +130,19 @@ void Inheritance(MessageHandler *m, Param &param, ReplyOnce &reply) {
result->id = std::to_string(param.usr);
result->usr = param.usr;
result->kind = param.kind;
if (!(((param.kind == Kind::Func && m->db->HasFunc(param.usr)) ||
(param.kind == Kind::Type && m->db->HasType(param.usr))) &&
Expand(m, &*result, param.derived, param.qualified, param.levels)))
if (!(((param.kind == Kind::Func && m->db->hasFunc(param.usr)) ||
(param.kind == Kind::Type && m->db->hasType(param.usr))) &&
expand(m, &*result, param.derived, param.qualified, param.levels)))
result.reset();
} else {
auto [file, wf] = m->FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = m->findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf) {
return;
}
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position))
if (sym.kind == Kind::Func || sym.kind == Kind::Type) {
result = BuildInitial(m, sym, param.derived, param.qualified,
param.levels);
result =
buildInitial(m, sym, param.derived, param.qualified, param.levels);
break;
}
}
@ -149,14 +150,14 @@ void Inheritance(MessageHandler *m, Param &param, ReplyOnce &reply) {
if (param.hierarchy)
reply(result);
else
reply(FlattenHierarchy(result));
reply(flattenHierarchy(result));
}
} // namespace
void MessageHandler::ccls_inheritance(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
Inheritance(this, param, reply);
reflect(reader, param);
inheritance(this, param, reply);
}
void MessageHandler::textDocument_implementation(
@ -165,6 +166,6 @@ void MessageHandler::textDocument_implementation(
param1.textDocument = param.textDocument;
param1.position = param.position;
param1.derived = true;
Inheritance(this, param1, reply);
inheritance(this, param1, reply);
}
} // namespace ccls

View File

@ -48,13 +48,13 @@ struct Out_cclsMember {
REFLECT_STRUCT(Out_cclsMember, id, name, fieldName, location, numChildren,
children);
bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
bool expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
int levels, Kind memberKind);
// Add a field to |entry| which is a Func/Type.
void DoField(MessageHandler *m, Out_cclsMember *entry, const QueryVar &var,
void doField(MessageHandler *m, Out_cclsMember *entry, const QueryVar &var,
int64_t offset, bool qualified, int levels) {
const QueryVar::Def *def1 = var.AnyDef();
const QueryVar::Def *def1 = var.anyDef();
if (!def1)
return;
Out_cclsMember entry1;
@ -74,17 +74,17 @@ void DoField(MessageHandler *m, Out_cclsMember *entry, const QueryVar &var,
else {
entry1.fieldName +=
std::string_view(def1->detailed_name).substr(0, def1->qual_name_offset);
entry1.fieldName += def1->Name(false);
entry1.fieldName += def1->name(false);
}
if (def1->spell) {
if (std::optional<Location> loc =
GetLsLocation(m->db, m->wfiles, *def1->spell))
getLsLocation(m->db, m->wfiles, *def1->spell))
entry1.location = *loc;
}
if (def1->type) {
entry1.id = std::to_string(def1->type);
entry1.usr = def1->type;
if (Expand(m, &entry1, qualified, levels, Kind::Var))
if (expand(m, &entry1, qualified, levels, Kind::Var))
entry->children.push_back(std::move(entry1));
} else {
entry1.id = "0";
@ -94,18 +94,18 @@ void DoField(MessageHandler *m, Out_cclsMember *entry, const QueryVar &var,
}
// Expand a type node by adding members recursively to it.
bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
bool expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
int levels, Kind memberKind) {
if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
entry->name = ClangBuiltinTypeName(int(entry->usr));
entry->name = clangBuiltinTypeName(int(entry->usr));
return true;
}
const QueryType *type = &m->db->Type(entry->usr);
const QueryType::Def *def = type->AnyDef();
const QueryType *type = &m->db->getType(entry->usr);
const QueryType::Def *def = type->anyDef();
// builtin types have no declaration and empty |qualified|.
if (!def)
return false;
entry->name = def->Name(qualified);
entry->name = def->name(qualified);
std::unordered_set<Usr> seen;
if (levels > 0) {
std::vector<const QueryType *> stack;
@ -114,37 +114,37 @@ bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
while (stack.size()) {
type = stack.back();
stack.pop_back();
const auto *def = type->AnyDef();
const auto *def = type->anyDef();
if (!def)
continue;
if (def->kind != SymbolKind::Namespace)
for (Usr usr : def->bases) {
auto &type1 = m->db->Type(usr);
auto &type1 = m->db->getType(usr);
if (type1.def.size()) {
seen.insert(type1.usr);
stack.push_back(&type1);
}
}
if (def->alias_of) {
const QueryType::Def *def1 = m->db->Type(def->alias_of).AnyDef();
const QueryType::Def *def1 = m->db->getType(def->alias_of).anyDef();
Out_cclsMember entry1;
entry1.id = std::to_string(def->alias_of);
entry1.usr = def->alias_of;
if (def1 && def1->spell) {
// The declaration of target type.
if (std::optional<Location> loc =
GetLsLocation(m->db, m->wfiles, *def1->spell))
getLsLocation(m->db, m->wfiles, *def1->spell))
entry1.location = *loc;
} else if (def->spell) {
// Builtin types have no declaration but the typedef declaration
// itself is useful.
if (std::optional<Location> loc =
GetLsLocation(m->db, m->wfiles, *def->spell))
getLsLocation(m->db, m->wfiles, *def->spell))
entry1.location = *loc;
}
if (def1 && qualified)
entry1.fieldName = def1->detailed_name;
if (Expand(m, &entry1, qualified, levels - 1, memberKind)) {
if (expand(m, &entry1, qualified, levels - 1, memberKind)) {
// For builtin types |name| is set.
if (entry1.fieldName.empty())
entry1.fieldName = std::string(entry1.name);
@ -155,15 +155,15 @@ bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
for (auto &def : type->def)
for (Usr usr : def.funcs)
if (seen1.insert(usr).second) {
QueryFunc &func1 = m->db->Func(usr);
if (const QueryFunc::Def *def1 = func1.AnyDef()) {
QueryFunc &func1 = m->db->getFunc(usr);
if (const QueryFunc::Def *def1 = func1.anyDef()) {
Out_cclsMember entry1;
entry1.fieldName = def1->Name(false);
entry1.fieldName = def1->name(false);
if (def1->spell) {
if (auto loc = GetLsLocation(m->db, m->wfiles, *def1->spell))
if (auto loc = getLsLocation(m->db, m->wfiles, *def1->spell))
entry1.location = *loc;
} else if (func1.declarations.size()) {
if (auto loc = GetLsLocation(m->db, m->wfiles,
if (auto loc = getLsLocation(m->db, m->wfiles,
func1.declarations[0]))
entry1.location = *loc;
}
@ -175,15 +175,15 @@ bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
for (auto &def : type->def)
for (Usr usr : def.types)
if (seen1.insert(usr).second) {
QueryType &type1 = m->db->Type(usr);
if (const QueryType::Def *def1 = type1.AnyDef()) {
QueryType &type1 = m->db->getType(usr);
if (const QueryType::Def *def1 = type1.anyDef()) {
Out_cclsMember entry1;
entry1.fieldName = def1->Name(false);
entry1.fieldName = def1->name(false);
if (def1->spell) {
if (auto loc = GetLsLocation(m->db, m->wfiles, *def1->spell))
if (auto loc = getLsLocation(m->db, m->wfiles, *def1->spell))
entry1.location = *loc;
} else if (type1.declarations.size()) {
if (auto loc = GetLsLocation(m->db, m->wfiles,
if (auto loc = getLsLocation(m->db, m->wfiles,
type1.declarations[0]))
entry1.location = *loc;
}
@ -195,9 +195,9 @@ bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
for (auto &def : type->def)
for (auto it : def.vars)
if (seen1.insert(it.first).second) {
QueryVar &var = m->db->Var(it.first);
QueryVar &var = m->db->getVar(it.first);
if (!var.def.empty())
DoField(m, entry, var, it.second, qualified, levels - 1);
doField(m, entry, var, it.second, qualified, levels - 1);
}
}
}
@ -207,33 +207,33 @@ bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
return true;
}
std::optional<Out_cclsMember> BuildInitial(MessageHandler *m, Kind kind,
std::optional<Out_cclsMember> buildInitial(MessageHandler *m, Kind kind,
Usr root_usr, bool qualified,
int levels, Kind memberKind) {
switch (kind) {
default:
return {};
case Kind::Func: {
const auto *def = m->db->Func(root_usr).AnyDef();
const auto *def = m->db->getFunc(root_usr).anyDef();
if (!def)
return {};
Out_cclsMember entry;
// Not type, |id| is invalid.
entry.name = def->Name(qualified);
entry.name = def->name(qualified);
if (def->spell) {
if (auto loc = GetLsLocation(m->db, m->wfiles, *def->spell))
if (auto loc = getLsLocation(m->db, m->wfiles, *def->spell))
entry.location = *loc;
}
for (Usr usr : def->vars) {
auto &var = m->db->Var(usr);
auto &var = m->db->getVar(usr);
if (var.def.size())
DoField(m, &entry, var, -1, qualified, levels - 1);
doField(m, &entry, var, -1, qualified, levels - 1);
}
return entry;
}
case Kind::Type: {
const auto *def = m->db->Type(root_usr).AnyDef();
const auto *def = m->db->getType(root_usr).anyDef();
if (!def)
return {};
@ -241,10 +241,10 @@ std::optional<Out_cclsMember> BuildInitial(MessageHandler *m, Kind kind,
entry.id = std::to_string(root_usr);
entry.usr = root_usr;
if (def->spell) {
if (auto loc = GetLsLocation(m->db, m->wfiles, *def->spell))
if (auto loc = getLsLocation(m->db, m->wfiles, *def->spell))
entry.location = *loc;
}
Expand(m, &entry, qualified, levels, memberKind);
expand(m, &entry, qualified, levels, memberKind);
return entry;
}
}
@ -253,7 +253,7 @@ std::optional<Out_cclsMember> BuildInitial(MessageHandler *m, Kind kind,
void MessageHandler::ccls_member(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
reflect(reader, param);
std::optional<Out_cclsMember> result;
if (param.id.size()) {
try {
@ -265,24 +265,24 @@ void MessageHandler::ccls_member(JsonReader &reader, ReplyOnce &reply) {
result->id = std::to_string(param.usr);
result->usr = param.usr;
// entry.name is empty as it is known by the client.
if (!(db->HasType(param.usr) && Expand(this, &*result, param.qualified,
param.levels, param.kind)))
if (!(db->hasType(param.usr) &&
expand(this, &*result, param.qualified, param.levels, param.kind)))
result.reset();
} else {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
switch (sym.kind) {
case Kind::Func:
case Kind::Type:
result = BuildInitial(this, sym.kind, sym.usr, param.qualified,
result = buildInitial(this, sym.kind, sym.usr, param.qualified,
param.levels, param.kind);
break;
case Kind::Var: {
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
const QueryVar::Def *def = db->getVar(sym).anyDef();
if (def && def->type)
result = BuildInitial(this, Kind::Type, def->type, param.qualified,
result = buildInitial(this, Kind::Type, def->type, param.qualified,
param.levels, param.kind);
break;
}
@ -296,6 +296,6 @@ void MessageHandler::ccls_member(JsonReader &reader, ReplyOnce &reply) {
if (param.hierarchy)
reply(result);
else
reply(FlattenHierarchy(result));
reply(flattenHierarchy(result));
}
} // namespace ccls

View File

@ -13,10 +13,10 @@ struct Param {
};
REFLECT_STRUCT(Param, textDocument, position, direction);
Maybe<Range> FindParent(QueryFile *file, Pos pos) {
Maybe<Range> findParent(QueryFile *file, Pos pos) {
Maybe<Range> parent;
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.extent.Valid() && sym.extent.start <= pos &&
if (refcnt > 0 && sym.extent.valid() && sym.extent.start <= pos &&
pos < sym.extent.end &&
(!parent || (parent->start == sym.extent.start
? parent->end < sym.extent.end
@ -28,22 +28,22 @@ Maybe<Range> FindParent(QueryFile *file, Pos pos) {
void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
reflect(reader, param);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf) {
return;
}
Position ls_pos = param.position;
if (wf->index_lines.size())
if (auto line =
wf->GetIndexPosFromBufferPos(ls_pos.line, &ls_pos.character, false))
wf->getIndexPosFromBufferPos(ls_pos.line, &ls_pos.character, false))
ls_pos.line = *line;
Pos pos{(uint16_t)ls_pos.line, (int16_t)ls_pos.character};
Maybe<Range> res;
switch (param.direction[0]) {
case 'D': {
Maybe<Range> parent = FindParent(file, pos);
Maybe<Range> parent = findParent(file, pos);
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && pos < sym.extent.start &&
(!parent || sym.extent.end <= parent->end) &&
@ -53,20 +53,20 @@ void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) {
}
case 'L':
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.extent.Valid() && sym.extent.end <= pos &&
if (refcnt > 0 && sym.extent.valid() && sym.extent.end <= pos &&
(!res || (res->end == sym.extent.end ? sym.extent.start < res->start
: res->end < sym.extent.end)))
res = sym.extent;
break;
case 'R': {
Maybe<Range> parent = FindParent(file, pos);
Maybe<Range> parent = findParent(file, pos);
if (parent && parent->start.line == pos.line && pos < parent->end) {
pos = parent->end;
if (pos.column)
pos.column--;
}
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.extent.Valid() && pos < sym.extent.start &&
if (refcnt > 0 && sym.extent.valid() && pos < sym.extent.start &&
(!res ||
(sym.extent.start == res->start ? res->end < sym.extent.end
: sym.extent.start < res->start)))
@ -76,14 +76,14 @@ void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) {
case 'U':
default:
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.extent.Valid() && sym.extent.start < pos &&
if (refcnt > 0 && sym.extent.valid() && sym.extent.start < pos &&
pos < sym.extent.end && (!res || res->start < sym.extent.start))
res = sym.extent;
break;
}
std::vector<Location> result;
if (res)
if (auto ls_range = GetLsRange(wf, *res)) {
if (auto ls_range = getLsRange(wf, *res)) {
Location &ls_loc = result.emplace_back();
ls_loc.uri = param.textDocument.uri;
ls_loc.range = *ls_range;

View File

@ -22,13 +22,13 @@ REFLECT_STRUCT(Param, dependencies, whitelist, blacklist);
void MessageHandler::ccls_reload(JsonReader &reader) {
Param param;
Reflect(reader, param);
reflect(reader, param);
// Send index requests for every file.
if (param.whitelist.empty() && param.blacklist.empty()) {
vfs->Clear();
vfs->clear();
db->clear();
project->Index(wfiles, RequestId());
manager->Clear();
project->index(wfiles, RequestId());
manager->clear();
return;
}
}

View File

@ -18,20 +18,20 @@ REFLECT_STRUCT(Param, textDocument, position, kind);
void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
reflect(reader, param);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf) {
return;
}
std::vector<Location> result;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
Usr usr = sym.usr;
switch (sym.kind) {
default:
break;
case Kind::Var: {
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
const QueryVar::Def *def = db->getVar(sym).anyDef();
if (!def || !def->type)
continue;
usr = def->type;
@ -39,8 +39,8 @@ void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
}
case Kind::Type: {
for (DeclRef dr :
GetVarDeclarations(db, db->Type(usr).instances, param.kind))
if (auto loc = GetLocationLink(db, wfiles, dr))
getVarDeclarations(db, db->getType(usr).instances, param.kind))
if (auto loc = getLocationLink(db, wfiles, dr))
result.push_back(Location(std::move(loc)));
break;
}

View File

@ -1,7 +1,6 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "sema_manager.hh"
#include "filesystem.hh"
#include "include_complete.hh"
#include "log.hh"
@ -9,6 +8,7 @@
#include "pipeline.hh"
#include "platform.hh"
#include "project.hh"
#include "sema_manager.hh"
#include "working_files.hh"
#include <llvm/ADT/Twine.h>
@ -17,8 +17,8 @@
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <stdlib.h>
#include <stdexcept>
#include <stdlib.h>
#include <thread>
namespace ccls {
@ -173,7 +173,8 @@ REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol,
hierarchicalDocumentSymbolSupport);
REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport);
REFLECT_STRUCT(TextDocumentClientCap::PublishDiagnostics, relatedInformation);
REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol, publishDiagnostics);
REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol,
publishDiagnostics);
struct ClientCap {
WorkspaceClientCap workspace;
@ -201,7 +202,7 @@ struct InitializeParam {
std::vector<WorkspaceFolder> workspaceFolders;
};
void Reflect(JsonReader &reader, InitializeParam::Trace &value) {
void reflect(JsonReader &reader, InitializeParam::Trace &value) {
if (!reader.m->IsString()) {
value = InitializeParam::Trace::Off;
return;
@ -241,7 +242,7 @@ REFLECT_STRUCT(DidChangeWatchedFilesRegistration::Option, watchers);
REFLECT_STRUCT(DidChangeWatchedFilesRegistration, id, method, registerOptions);
REFLECT_STRUCT(RegistrationParam, registrations);
void *Indexer(void *arg_) {
void *indexer(void *arg_) {
MessageHandler *h;
int idx;
auto *arg = static_cast<std::pair<MessageHandler *, int> *>(arg_);
@ -249,14 +250,15 @@ void *Indexer(void *arg_) {
delete arg;
std::string name = "indexer" + std::to_string(idx);
set_thread_name(name.c_str());
pipeline::Indexer_Main(h->manager, h->vfs, h->project, h->wfiles);
pipeline::ThreadLeave();
pipeline::indexer_Main(h->manager, h->vfs, h->project, h->wfiles);
pipeline::threadLeave();
return nullptr;
}
} // namespace
void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
std::string project_path = NormalizePath(param.rootUri->GetPath());
void do_initialize(MessageHandler *m, InitializeParam &param,
ReplyOnce &reply) {
std::string project_path = normalizePath(param.rootUri->getPath());
LOG_S(INFO) << "initialize in directory " << project_path << " with uri "
<< param.rootUri->raw_uri;
@ -268,7 +270,7 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
if (!reader.HasParseError()) {
JsonReader json_reader{&reader};
try {
Reflect(json_reader, *g_config);
reflect(json_reader, *g_config);
} catch (std::invalid_argument &) {
// This will not trigger because parse error is handled in
// MessageRegistry::Parse in lsp.cc
@ -279,15 +281,15 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
JsonWriter json_writer(&writer);
Reflect(json_writer, *g_config);
reflect(json_writer, *g_config);
LOG_S(INFO) << "initializationOptions: " << output.GetString();
if (g_config->cache.directory.size()) {
SmallString<256> Path(g_config->cache.directory);
sys::fs::make_absolute(project_path, Path);
SmallString<256> path(g_config->cache.directory);
sys::fs::make_absolute(project_path, path);
// Use upper case for the Driver letter on Windows.
g_config->cache.directory = NormalizePath(Path.str());
EnsureEndsInSlash(g_config->cache.directory);
g_config->cache.directory = normalizePath(path.str());
ensureEndsInSlash(g_config->cache.directory);
}
}
@ -307,8 +309,8 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
// Ensure there is a resource directory.
if (g_config->clang.resourceDir.empty())
g_config->clang.resourceDir = GetDefaultResourceDirectory();
DoPathMapping(g_config->clang.resourceDir);
g_config->clang.resourceDir = getDefaultResourceDirectory();
doPathMapping(g_config->clang.resourceDir);
LOG_S(INFO) << "use -resource-dir=" << g_config->clang.resourceDir;
// Send initialization before starting indexers, so we don't send a
@ -324,17 +326,17 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
}
// Set project root.
EnsureEndsInSlash(project_path);
ensureEndsInSlash(project_path);
g_config->fallbackFolder = project_path;
auto &workspaceFolders = g_config->workspaceFolders;
for (const WorkspaceFolder &wf : param.workspaceFolders) {
std::string path = wf.uri.GetPath();
EnsureEndsInSlash(path);
std::string real = RealPath(path) + '/';
std::string path = wf.uri.getPath();
ensureEndsInSlash(path);
std::string real = realPath(path) + '/';
workspaceFolders.emplace_back(path, path == real ? "" : real);
}
if (workspaceFolders.empty()) {
std::string real = RealPath(project_path) + '/';
std::string real = realPath(project_path) + '/';
workspaceFolders.emplace_back(project_path,
project_path == real ? "" : real);
}
@ -352,14 +354,14 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
for (auto &[folder, _] : workspaceFolders) {
// Create two cache directories for files inside and outside of the
// project.
std::string escaped = EscapeFileName(folder.substr(0, folder.size() - 1));
std::string escaped = escapeFileName(folder.substr(0, folder.size() - 1));
sys::fs::create_directories(g_config->cache.directory + escaped);
sys::fs::create_directories(g_config->cache.directory + '@' + escaped);
}
idx::Init();
idx::init();
for (auto &[folder, _] : workspaceFolders)
m->project->Load(folder);
m->project->load(folder);
// Start indexer threads. Start this after loading the project, as that
// may take a long time. Indexer threads will emit status/progress
@ -369,26 +371,26 @@ void Initialize(MessageHandler *m, InitializeParam &param, ReplyOnce &reply) {
LOG_S(INFO) << "start " << g_config->index.threads << " indexers";
for (int i = 0; i < g_config->index.threads; i++)
SpawnThread(Indexer, new std::pair<MessageHandler *, int>{m, i});
spawnThread(indexer, new std::pair<MessageHandler *, int>{m, i});
// Start scanning include directories before dispatching project
// files, because that takes a long time.
m->include_complete->Rescan();
m->include_complete->rescan();
LOG_S(INFO) << "dispatch initial index requests";
m->project->Index(m->wfiles, reply.id);
m->project->index(m->wfiles, reply.id);
m->manager->sessions.SetCapacity(g_config->session.maxNum);
m->manager->sessions.setCapacity(g_config->session.maxNum);
}
void MessageHandler::initialize(JsonReader &reader, ReplyOnce &reply) {
InitializeParam param;
Reflect(reader, param);
reflect(reader, param);
auto it = reader.m->FindMember("initializationOptions");
if (it != reader.m->MemberEnd() && it->value.IsObject()) {
JsonReader m1(&it->value);
try {
Reflect(m1, param.initializationOptions);
reflect(m1, param.initializationOptions);
} catch (std::invalid_argument &) {
reader.path_.push_back("initializationOptions");
reader.path_.insert(reader.path_.end(), m1.path_.begin(), m1.path_.end());
@ -396,23 +398,23 @@ void MessageHandler::initialize(JsonReader &reader, ReplyOnce &reply) {
}
}
if (!param.rootUri) {
reply.Error(ErrorCode::InvalidRequest, "expected rootUri");
reply.error(ErrorCode::InvalidRequest, "expected rootUri");
return;
}
Initialize(this, param, reply);
do_initialize(this, param, reply);
}
void StandaloneInitialize(MessageHandler &handler, const std::string &root) {
void standaloneInitialize(MessageHandler &handler, const std::string &root) {
InitializeParam param;
param.rootUri = DocumentUri::FromPath(root);
param.rootUri = DocumentUri::fromPath(root);
ReplyOnce reply{handler};
Initialize(&handler, param, reply);
do_initialize(&handler, param, reply);
}
void MessageHandler::initialized(EmptyParam &) {
if (didChangeWatchedFiles) {
RegistrationParam param;
pipeline::Request("client/registerCapability", param);
pipeline::request("client/registerCapability", param);
}
}
@ -421,6 +423,6 @@ void MessageHandler::shutdown(EmptyParam &, ReplyOnce &reply) {
}
void MessageHandler::exit(EmptyParam &) {
pipeline::quit.store(true, std::memory_order_relaxed);
pipeline::g_quit.store(true, std::memory_order_relaxed);
}
} // namespace ccls

View File

@ -20,20 +20,20 @@ struct CodeAction {
WorkspaceEdit edit;
};
REFLECT_STRUCT(CodeAction, title, kind, edit);
}
} // namespace
void MessageHandler::textDocument_codeAction(CodeActionParam &param,
ReplyOnce &reply) {
WorkingFile *wf = FindOrFail(param.textDocument.uri.GetPath(), reply).second;
WorkingFile *wf = findOrFail(param.textDocument.uri.getPath(), reply).second;
if (!wf)
return;
std::vector<CodeAction> result;
std::vector<Diagnostic> diagnostics;
wfiles->WithLock([&]() { diagnostics = wf->diagnostics; });
wfiles->withLock([&]() { diagnostics = wf->diagnostics; });
for (Diagnostic &diag : diagnostics)
if (diag.fixits_.size() &&
(param.range.Intersects(diag.range) ||
(param.range.intersects(diag.range) ||
llvm::any_of(diag.fixits_, [&](const TextEdit &edit) {
return param.range.Intersects(edit.range);
return param.range.intersects(edit.range);
}))) {
CodeAction &cmd = result.emplace_back();
cmd.title = "FixIt: " + diag.message;
@ -64,12 +64,11 @@ REFLECT_STRUCT(Cmd_xref, usr, kind, field);
REFLECT_STRUCT(Command, title, command, arguments);
REFLECT_STRUCT(CodeLens, range, command);
template <typename T>
std::string ToString(T &v) {
template <typename T> std::string toString(T &v) {
rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
JsonWriter json_writer(&writer);
Reflect(json_writer, v);
reflect(json_writer, v);
return output.GetString();
}
@ -82,16 +81,16 @@ struct CommonCodeLensParams {
void MessageHandler::textDocument_codeLens(TextDocumentParam &param,
ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
std::vector<CodeLens> result;
auto Add = [&, wf = wf](const char *singular, Cmd_xref show, Range range,
auto add = [&, wf = wf](const char *singular, Cmd_xref show, Range range,
int num, bool force_display = false) {
if (!num && !force_display)
return;
std::optional<lsRange> ls_range = GetLsRange(wf, range);
std::optional<lsRange> ls_range = getLsRange(wf, range);
if (!ls_range)
return;
CodeLens &code_lens = result.emplace_back();
@ -101,52 +100,52 @@ void MessageHandler::textDocument_codeLens(TextDocumentParam &param,
bool plural = num > 1 && singular[strlen(singular) - 1] != 'd';
code_lens.command->title =
llvm::formatv("{0} {1}{2}", num, singular, plural ? "s" : "").str();
code_lens.command->arguments.push_back(ToString(show));
code_lens.command->arguments.push_back(toString(show));
};
std::unordered_set<Range> seen;
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0 || !sym.extent.Valid() || !seen.insert(sym.range).second)
if (refcnt <= 0 || !sym.extent.valid() || !seen.insert(sym.range).second)
continue;
switch (sym.kind) {
case Kind::Func: {
QueryFunc &func = db->GetFunc(sym);
const QueryFunc::Def *def = func.AnyDef();
QueryFunc &func = db->getFunc(sym);
const QueryFunc::Def *def = func.anyDef();
if (!def)
continue;
std::vector<Use> base_uses = GetUsesForAllBases(db, func);
std::vector<Use> derived_uses = GetUsesForAllDerived(db, func);
Add("ref", {sym.usr, Kind::Func, "uses"}, sym.range, func.uses.size(),
std::vector<Use> base_uses = getUsesForAllBases(db, func);
std::vector<Use> derived_uses = getUsesForAllDerived(db, func);
add("ref", {sym.usr, Kind::Func, "uses"}, sym.range, func.uses.size(),
base_uses.empty());
if (base_uses.size())
Add("b.ref", {sym.usr, Kind::Func, "bases uses"}, sym.range,
add("b.ref", {sym.usr, Kind::Func, "bases uses"}, sym.range,
base_uses.size());
if (derived_uses.size())
Add("d.ref", {sym.usr, Kind::Func, "derived uses"}, sym.range,
add("d.ref", {sym.usr, Kind::Func, "derived uses"}, sym.range,
derived_uses.size());
if (base_uses.empty())
Add("base", {sym.usr, Kind::Func, "bases"}, sym.range,
add("base", {sym.usr, Kind::Func, "bases"}, sym.range,
def->bases.size());
Add("derived", {sym.usr, Kind::Func, "derived"}, sym.range,
add("derived", {sym.usr, Kind::Func, "derived"}, sym.range,
func.derived.size());
break;
}
case Kind::Type: {
QueryType &type = db->GetType(sym);
Add("ref", {sym.usr, Kind::Type, "uses"}, sym.range, type.uses.size(),
QueryType &type = db->getType(sym);
add("ref", {sym.usr, Kind::Type, "uses"}, sym.range, type.uses.size(),
true);
Add("derived", {sym.usr, Kind::Type, "derived"}, sym.range,
add("derived", {sym.usr, Kind::Type, "derived"}, sym.range,
type.derived.size());
Add("var", {sym.usr, Kind::Type, "instances"}, sym.range,
add("var", {sym.usr, Kind::Type, "instances"}, sym.range,
type.instances.size());
break;
}
case Kind::Var: {
QueryVar &var = db->GetVar(sym);
const QueryVar::Def *def = var.AnyDef();
QueryVar &var = db->getVar(sym);
const QueryVar::Def *def = var.anyDef();
if (!def || (def->is_local() && !g_config->codeLens.localVariables))
continue;
Add("ref", {sym.usr, Kind::Var, "uses"}, sym.range, var.uses.size(),
add("ref", {sym.usr, Kind::Var, "uses"}, sym.range, var.uses.size(),
def->kind != SymbolKind::Macro);
break;
}
@ -162,7 +161,7 @@ void MessageHandler::textDocument_codeLens(TextDocumentParam &param,
void MessageHandler::workspace_executeCommand(JsonReader &reader,
ReplyOnce &reply) {
Command param;
Reflect(reader, param);
reflect(reader, param);
if (param.arguments.empty()) {
return;
}
@ -171,45 +170,45 @@ void MessageHandler::workspace_executeCommand(JsonReader &reader,
JsonReader json_reader{&reader1};
if (param.command == ccls_xref) {
Cmd_xref cmd;
Reflect(json_reader, cmd);
reflect(json_reader, cmd);
std::vector<Location> result;
auto Map = [&](auto &&uses) {
auto map = [&](auto &&uses) {
for (auto &use : uses)
if (auto loc = GetLsLocation(db, wfiles, use))
if (auto loc = getLsLocation(db, wfiles, use))
result.push_back(std::move(*loc));
};
switch (cmd.kind) {
case Kind::Func: {
QueryFunc &func = db->Func(cmd.usr);
QueryFunc &func = db->getFunc(cmd.usr);
if (cmd.field == "bases") {
if (auto *def = func.AnyDef())
Map(GetFuncDeclarations(db, def->bases));
if (auto *def = func.anyDef())
map(getFuncDeclarations(db, def->bases));
} else if (cmd.field == "bases uses") {
Map(GetUsesForAllBases(db, func));
map(getUsesForAllBases(db, func));
} else if (cmd.field == "derived") {
Map(GetFuncDeclarations(db, func.derived));
map(getFuncDeclarations(db, func.derived));
} else if (cmd.field == "derived uses") {
Map(GetUsesForAllDerived(db, func));
map(getUsesForAllDerived(db, func));
} else if (cmd.field == "uses") {
Map(func.uses);
map(func.uses);
}
break;
}
case Kind::Type: {
QueryType &type = db->Type(cmd.usr);
QueryType &type = db->getType(cmd.usr);
if (cmd.field == "derived") {
Map(GetTypeDeclarations(db, type.derived));
map(getTypeDeclarations(db, type.derived));
} else if (cmd.field == "instances") {
Map(GetVarDeclarations(db, type.instances, 7));
map(getVarDeclarations(db, type.instances, 7));
} else if (cmd.field == "uses") {
Map(type.uses);
map(type.uses);
}
break;
}
case Kind::Var: {
QueryVar &var = db->Var(cmd.usr);
QueryVar &var = db->getVar(cmd.usr);
if (cmd.field == "uses")
Map(var.uses);
map(var.uses);
break;
}
default:

View File

@ -23,8 +23,8 @@ using namespace llvm;
REFLECT_UNDERLYING(InsertTextFormat);
REFLECT_UNDERLYING(CompletionItemKind);
void Reflect(JsonWriter &vis, CompletionItem &v) {
ReflectMemberStart(vis);
void reflect(JsonWriter &vis, CompletionItem &v) {
reflectMemberStart(vis);
REFLECT_MEMBER(label);
REFLECT_MEMBER(kind);
REFLECT_MEMBER(detail);
@ -37,7 +37,7 @@ void Reflect(JsonWriter &vis, CompletionItem &v) {
REFLECT_MEMBER(textEdit);
if (v.additionalTextEdits.size())
REFLECT_MEMBER(additionalTextEdits);
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
namespace {
@ -48,9 +48,8 @@ struct CompletionList {
REFLECT_STRUCT(CompletionList, isIncomplete, items);
#if LLVM_VERSION_MAJOR < 8
void DecorateIncludePaths(const std::smatch &match,
std::vector<CompletionItem> *items,
char quote) {
void decorateIncludePaths(const std::smatch &match,
std::vector<CompletionItem> *items, char quote) {
std::string spaces_after_include = " ";
if (match[3].compare("include") == 0 && quote != '\0')
spaces_after_include = match[4].str();
@ -99,7 +98,7 @@ ParseIncludeLineResult ParseIncludeLine(const std::string &line) {
// Pre-filters completion responses before sending to vscode. This results in a
// significantly snappier completion experience as vscode is easily overloaded
// when given 1000+ completion items.
void FilterCandidates(CompletionList &result, const std::string &complete_text,
void filterCandidates(CompletionList &result, const std::string &complete_text,
Position begin_pos, Position end_pos,
const std::string &buffer_line) {
assert(begin_pos.line == end_pos.line);
@ -149,12 +148,15 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text,
auto &edits = item.additionalTextEdits;
if (overwrite_len > 0) {
item.textEdit.range.start = overwrite_begin;
std::string orig = buffer_line.substr(overwrite_begin.character, overwrite_len);
std::string orig =
buffer_line.substr(overwrite_begin.character, overwrite_len);
if (edits.size() && edits[0].range.end == begin_pos &&
edits[0].range.start.line == begin_pos.line) {
int cur_edit_len = edits[0].range.end.character - edits[0].range.start.character;
int cur_edit_len =
edits[0].range.end.character - edits[0].range.start.character;
item.textEdit.newText =
buffer_line.substr(overwrite_begin.character, overwrite_len - cur_edit_len) +
buffer_line.substr(overwrite_begin.character,
overwrite_len - cur_edit_len) +
edits[0].newText + item.textEdit.newText;
edits.erase(edits.begin());
} else {
@ -182,8 +184,8 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text,
for (CompletionItem &item : items) {
const std::string &filter =
item.filterText.size() ? item.filterText : item.label;
item.score_ = ReverseSubseqMatch(complete_text, filter, sensitive) >= 0
? fuzzy.Match(filter, true)
item.score_ = reverseSubseqMatch(complete_text, filter, sensitive) >= 0
? fuzzy.match(filter, true)
: FuzzyMatcher::kMinScore;
}
items.erase(std::remove_if(items.begin(), items.end(),
@ -215,12 +217,12 @@ void FilterCandidates(CompletionList &result, const std::string &complete_text,
finalize();
}
CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
const CodeCompletionResult &R) {
switch (R.Kind) {
CompletionItemKind getCompletionKind(CodeCompletionContext::Kind k,
const CodeCompletionResult &r) {
switch (r.Kind) {
case CodeCompletionResult::RK_Declaration: {
const Decl *D = R.Declaration;
switch (D->getKind()) {
const Decl *d = r.Declaration;
switch (d->getKind()) {
case Decl::LinkageSpec:
return CompletionItemKind::Keyword;
case Decl::Namespace:
@ -243,7 +245,7 @@ CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
case Decl::TypeAliasTemplate:
return CompletionItemKind::Class;
case Decl::VarTemplate:
if (cast<VarTemplateDecl>(D)->getTemplatedDecl()->isConstexpr())
if (cast<VarTemplateDecl>(d)->getTemplatedDecl()->isConstexpr())
return CompletionItemKind::Constant;
return CompletionItemKind::Variable;
case Decl::TemplateTemplateParm:
@ -252,8 +254,8 @@ CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
return CompletionItemKind::Enum;
case Decl::CXXRecord:
case Decl::Record:
if (auto *RD = dyn_cast<RecordDecl>(D))
if (RD->getTagKind() == TTK_Struct)
if (auto *rd = dyn_cast<RecordDecl>(d))
if (rd->getTagKind() == TTK_Struct)
return CompletionItemKind::Struct;
return CompletionItemKind::Class;
case Decl::TemplateTypeParm:
@ -283,7 +285,7 @@ CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
case Decl::ParmVar:
case Decl::VarTemplateSpecialization:
case Decl::VarTemplatePartialSpecialization:
if (cast<VarDecl>(D)->isConstexpr())
if (cast<VarDecl>(d)->isConstexpr())
return CompletionItemKind::Constant;
return CompletionItemKind::Variable;
case Decl::EnumConstant:
@ -292,7 +294,7 @@ CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
return CompletionItemKind::Field;
default:
LOG_S(WARNING) << "Unhandled " << int(D->getKind());
LOG_S(WARNING) << "Unhandled " << int(d->getKind());
return CompletionItemKind::Text;
}
break;
@ -303,41 +305,41 @@ CompletionItemKind GetCompletionKind(CodeCompletionContext::Kind K,
return CompletionItemKind::Reference;
case CodeCompletionResult::RK_Pattern:
#if LLVM_VERSION_MAJOR >= 8
if (K == CodeCompletionContext::CCC_IncludedFile)
if (k == CodeCompletionContext::CCC_IncludedFile)
return CompletionItemKind::File;
#endif
return CompletionItemKind::Snippet;
}
}
void BuildItem(const CodeCompletionResult &R, const CodeCompletionString &CCS,
void buildItem(const CodeCompletionResult &r, const CodeCompletionString &ccs,
std::vector<CompletionItem> &out) {
assert(!out.empty());
auto first = out.size() - 1;
bool ignore = false;
std::string result_type;
for (const auto &Chunk : CCS) {
CodeCompletionString::ChunkKind Kind = Chunk.Kind;
for (const auto &chunk : ccs) {
CodeCompletionString::ChunkKind kind = chunk.Kind;
std::string text;
switch (Kind) {
switch (kind) {
case CodeCompletionString::CK_TypedText:
text = Chunk.Text;
text = chunk.Text;
for (auto i = first; i < out.size(); i++)
out[i].filterText = text;
break;
case CodeCompletionString::CK_Placeholder:
text = Chunk.Text;
text = chunk.Text;
for (auto i = first; i < out.size(); i++)
out[i].parameters_.push_back(text);
break;
case CodeCompletionString::CK_Informative:
if (StringRef(Chunk.Text).endswith("::"))
if (StringRef(chunk.Text).endswith("::"))
continue;
text = Chunk.Text;
text = chunk.Text;
break;
case CodeCompletionString::CK_ResultType:
result_type = Chunk.Text;
result_type = chunk.Text;
continue;
case CodeCompletionString::CK_CurrentParameter:
// This should never be present while collecting completion items.
@ -347,12 +349,12 @@ void BuildItem(const CodeCompletionResult &R, const CodeCompletionString &CCS,
// Duplicate last element, the recursive call will complete it.
if (g_config->completion.duplicateOptional) {
out.push_back(out.back());
BuildItem(R, *Chunk.Optional, out);
buildItem(r, *chunk.Optional, out);
}
continue;
}
default:
text = Chunk.Text;
text = chunk.Text;
break;
}
@ -362,15 +364,15 @@ void BuildItem(const CodeCompletionResult &R, const CodeCompletionString &CCS,
(!g_config->client.snippetSupport && out[i].parameters_.size()))
continue;
if (Kind == CodeCompletionString::CK_Placeholder) {
if (R.Kind == CodeCompletionResult::RK_Pattern) {
if (kind == CodeCompletionString::CK_Placeholder) {
if (r.Kind == CodeCompletionResult::RK_Pattern) {
ignore = true;
continue;
}
out[i].textEdit.newText +=
"${" + std::to_string(out[i].parameters_.size()) + ":" + text + "}";
out[i].insertTextFormat = InsertTextFormat::Snippet;
} else if (Kind != CodeCompletionString::CK_Informative) {
} else if (kind != CodeCompletionString::CK_Informative) {
out[i].textEdit.newText += text;
}
}
@ -386,98 +388,99 @@ void BuildItem(const CodeCompletionResult &R, const CodeCompletionString &CCS,
}
class CompletionConsumer : public CodeCompleteConsumer {
std::shared_ptr<clang::GlobalCodeCompletionAllocator> Alloc;
CodeCompletionTUInfo CCTUInfo;
std::shared_ptr<clang::GlobalCodeCompletionAllocator> alloc;
CodeCompletionTUInfo cctu_info;
public:
bool from_cache;
std::vector<CompletionItem> ls_items;
CompletionConsumer(const CodeCompleteOptions &Opts, bool from_cache)
CompletionConsumer(const CodeCompleteOptions &opts, bool from_cache)
:
#if LLVM_VERSION_MAJOR >= 9 // rC358696
CodeCompleteConsumer(Opts),
CodeCompleteConsumer(opts),
#else
CodeCompleteConsumer(Opts, false),
CodeCompleteConsumer(opts, false),
#endif
Alloc(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
CCTUInfo(Alloc), from_cache(from_cache) {}
alloc(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
cctu_info(alloc), from_cache(from_cache) {
}
void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults) override {
if (Context.getKind() == CodeCompletionContext::CCC_Recovery)
void ProcessCodeCompleteResults(Sema &s, CodeCompletionContext context,
CodeCompletionResult *results,
unsigned numResults) override {
if (context.getKind() == CodeCompletionContext::CCC_Recovery)
return;
ls_items.reserve(NumResults);
for (unsigned i = 0; i != NumResults; i++) {
auto &R = Results[i];
if (R.Availability == CXAvailability_NotAccessible ||
R.Availability == CXAvailability_NotAvailable)
ls_items.reserve(numResults);
for (unsigned i = 0; i != numResults; i++) {
auto &r = results[i];
if (r.Availability == CXAvailability_NotAccessible ||
r.Availability == CXAvailability_NotAvailable)
continue;
if (R.Declaration) {
Decl::Kind K = R.Declaration->getKind();
if (K == Decl::CXXDestructor)
if (r.Declaration) {
Decl::Kind k = r.Declaration->getKind();
if (k == Decl::CXXDestructor)
continue;
if (K == Decl::FunctionTemplate) {
if (k == Decl::FunctionTemplate) {
// Ignore CXXDeductionGuide which has empty TypedText.
auto *FD = cast<FunctionTemplateDecl>(R.Declaration);
if (FD->getTemplatedDecl()->getKind() == Decl::CXXDeductionGuide)
auto *fd = cast<FunctionTemplateDecl>(r.Declaration);
if (fd->getTemplatedDecl()->getKind() == Decl::CXXDeductionGuide)
continue;
}
if (auto *RD = dyn_cast<RecordDecl>(R.Declaration))
if (RD->isInjectedClassName())
if (auto *rd = dyn_cast<RecordDecl>(r.Declaration))
if (rd->isInjectedClassName())
continue;
auto NK = R.Declaration->getDeclName().getNameKind();
if (NK == DeclarationName::CXXOperatorName ||
NK == DeclarationName::CXXLiteralOperatorName)
auto nk = r.Declaration->getDeclName().getNameKind();
if (nk == DeclarationName::CXXOperatorName ||
nk == DeclarationName::CXXLiteralOperatorName)
continue;
}
CodeCompletionString *CCS = R.CreateCodeCompletionString(
S, Context, getAllocator(), getCodeCompletionTUInfo(),
CodeCompletionString *ccs = r.CreateCodeCompletionString(
s, context, getAllocator(), getCodeCompletionTUInfo(),
includeBriefComments());
CompletionItem ls_item;
ls_item.kind = GetCompletionKind(Context.getKind(), R);
if (const char *brief = CCS->getBriefComment())
ls_item.kind = getCompletionKind(context.getKind(), r);
if (const char *brief = ccs->getBriefComment())
ls_item.documentation = brief;
ls_item.detail = CCS->getParentContextName().str();
ls_item.detail = ccs->getParentContextName().str();
size_t first_idx = ls_items.size();
ls_items.push_back(ls_item);
BuildItem(R, *CCS, ls_items);
buildItem(r, *ccs, ls_items);
for (size_t j = first_idx; j < ls_items.size(); j++) {
if (g_config->client.snippetSupport &&
ls_items[j].insertTextFormat == InsertTextFormat::Snippet)
ls_items[j].textEdit.newText += "$0";
ls_items[j].priority_ = CCS->getPriority();
ls_items[j].priority_ = ccs->getPriority();
if (!g_config->completion.detailedLabel) {
ls_items[j].detail = ls_items[j].label;
ls_items[j].label = ls_items[j].filterText;
}
}
for (const FixItHint &FixIt : R.FixIts) {
auto &AST = S.getASTContext();
for (const FixItHint &fixIt : r.FixIts) {
auto &ast = s.getASTContext();
TextEdit ls_edit =
ccls::ToTextEdit(AST.getSourceManager(), AST.getLangOpts(), FixIt);
ccls::toTextEdit(ast.getSourceManager(), ast.getLangOpts(), fixIt);
for (size_t j = first_idx; j < ls_items.size(); j++)
ls_items[j].additionalTextEdits.push_back(ls_edit);
}
}
}
CodeCompletionAllocator &getAllocator() override { return *Alloc; }
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
CodeCompletionAllocator &getAllocator() override { return *alloc; }
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return cctu_info; }
};
} // namespace
void MessageHandler::textDocument_completion(CompletionParam &param,
ReplyOnce &reply) {
static CompleteConsumerCache<std::vector<CompletionItem>> cache;
std::string path = param.textDocument.uri.GetPath();
WorkingFile *wf = wfiles->GetFile(path);
std::string path = param.textDocument.uri.getPath();
WorkingFile *wf = wfiles->getFile(path);
if (!wf) {
reply.NotOpened(path);
reply.notOpened(path);
return;
}
@ -489,11 +492,11 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
if (param.position.line >= 0 && param.position.line < wf->buffer_lines.size())
buffer_line = wf->buffer_lines[param.position.line];
clang::CodeCompleteOptions CCOpts;
CCOpts.IncludeBriefComments = true;
CCOpts.IncludeCodePatterns = StringRef(buffer_line).ltrim().startswith("#");
CCOpts.IncludeFixIts = true;
CCOpts.IncludeMacros = true;
clang::CodeCompleteOptions ccOpts;
ccOpts.IncludeBriefComments = true;
ccOpts.IncludeCodePatterns = StringRef(buffer_line).ltrim().startswith("#");
ccOpts.IncludeFixIts = true;
ccOpts.IncludeMacros = true;
if (param.context.triggerKind == CompletionTriggerKind::TriggerCharacter &&
param.context.triggerCharacter) {
@ -503,7 +506,7 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
case '"':
case '/':
case '<':
ok = CCOpts.IncludeCodePatterns; // start with #
ok = ccOpts.IncludeCodePatterns; // start with #
break;
case ':':
ok = col >= 0 && buffer_line[col] == ':'; // ::
@ -521,7 +524,7 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
std::string filter;
Position end_pos;
Position begin_pos =
wf->GetCompletionPosition(param.position, &filter, &end_pos);
wf->getCompletionPosition(param.position, &filter, &end_pos);
#if LLVM_VERSION_MAJOR < 8
ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line);
@ -540,9 +543,9 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
}
begin_pos.character = 0;
end_pos.character = (int)buffer_line.size();
FilterCandidates(result, preprocess.pattern, begin_pos, end_pos,
filterCandidates(result, preprocess.pattern, begin_pos, end_pos,
buffer_line);
DecorateIncludePaths(preprocess.match, &result.items, quote);
decorateIncludePaths(preprocess.match, &result.items, quote);
reply(result);
return;
}
@ -550,32 +553,32 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
SemaManager::OnComplete callback =
[filter, path, begin_pos, end_pos, reply,
buffer_line](CodeCompleteConsumer *OptConsumer) {
if (!OptConsumer)
buffer_line](CodeCompleteConsumer *optConsumer) {
if (!optConsumer)
return;
auto *Consumer = static_cast<CompletionConsumer *>(OptConsumer);
auto *consumer = static_cast<CompletionConsumer *>(optConsumer);
CompletionList result;
result.items = Consumer->ls_items;
result.items = consumer->ls_items;
FilterCandidates(result, filter, begin_pos, end_pos, buffer_line);
filterCandidates(result, filter, begin_pos, end_pos, buffer_line);
reply(result);
if (!Consumer->from_cache) {
cache.WithLock([&]() {
if (!consumer->from_cache) {
cache.withLock([&]() {
cache.path = path;
cache.position = begin_pos;
cache.result = Consumer->ls_items;
cache.result = consumer->ls_items;
});
}
};
if (cache.IsCacheValid(path, begin_pos)) {
CompletionConsumer Consumer(CCOpts, true);
cache.WithLock([&]() { Consumer.ls_items = cache.result; });
callback(&Consumer);
if (cache.isCacheValid(path, begin_pos)) {
CompletionConsumer consumer(ccOpts, true);
cache.withLock([&]() { consumer.ls_items = cache.result; });
callback(&consumer);
} else {
manager->comp_tasks.PushBack(std::make_unique<SemaManager::CompTask>(
reply.id, param.textDocument.uri.GetPath(), begin_pos,
std::make_unique<CompletionConsumer>(CCOpts, false), CCOpts, callback));
manager->comp_tasks.pushBack(std::make_unique<SemaManager::CompTask>(
reply.id, param.textDocument.uri.getPath(), begin_pos,
std::make_unique<CompletionConsumer>(ccOpts, false), ccOpts, callback));
}
}
} // namespace ccls

View File

@ -12,25 +12,27 @@ namespace ccls {
void MessageHandler::textDocument_declaration(TextDocumentPositionParam &param,
ReplyOnce &reply) {
int file_id;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
auto [file, wf] =
findOrFail(param.textDocument.uri.getPath(), reply, &file_id);
if (!wf)
return;
std::vector<LocationLink> result;
Position &ls_pos = param.position;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
for (DeclRef dr : GetNonDefDeclarations(db, sym))
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position))
for (DeclRef dr : getNonDefDeclarations(db, sym))
if (!(dr.file_id == file_id &&
dr.range.Contains(ls_pos.line, ls_pos.character)))
if (auto loc = GetLocationLink(db, wfiles, dr))
dr.range.contains(ls_pos.line, ls_pos.character)))
if (auto loc = getLocationLink(db, wfiles, dr))
result.push_back(loc);
reply.ReplyLocationLink(result);
reply.replyLocationLink(result);
}
void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
ReplyOnce &reply) {
int file_id;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
auto [file, wf] =
findOrFail(param.textDocument.uri.getPath(), reply, &file_id);
if (!wf)
return;
@ -38,16 +40,16 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
Maybe<DeclRef> on_def;
Position &ls_pos = param.position;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, ls_pos, true)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, ls_pos, true)) {
// Special cases which are handled:
// - symbol has declaration but no definition (ie, pure virtual)
// - goto declaration while in definition of recursive type
std::vector<DeclRef> drs;
EachEntityDef(db, sym, [&](const auto &def) {
eachEntityDef(db, sym, [&](const auto &def) {
if (def.spell) {
DeclRef spell = *def.spell;
if (spell.file_id == file_id &&
spell.range.Contains(ls_pos.line, ls_pos.character)) {
spell.range.contains(ls_pos.line, ls_pos.character)) {
on_def = spell;
drs.clear();
return false;
@ -60,16 +62,16 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
// |uses| is empty if on a declaration/definition, otherwise it includes
// all declarations/definitions.
if (drs.empty()) {
for (DeclRef dr : GetNonDefDeclarations(db, sym))
for (DeclRef dr : getNonDefDeclarations(db, sym))
if (!(dr.file_id == file_id &&
dr.range.Contains(ls_pos.line, ls_pos.character)))
dr.range.contains(ls_pos.line, ls_pos.character)))
drs.push_back(dr);
// There is no declaration but the cursor is on a definition.
if (drs.empty() && on_def)
drs.push_back(*on_def);
}
for (DeclRef dr : drs)
if (auto loc = GetLocationLink(db, wfiles, dr))
if (auto loc = getLocationLink(db, wfiles, dr))
result.push_back(loc);
}
@ -79,7 +81,7 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
for (const IndexInclude &include : file->def->includes) {
if (include.line == ls_pos.line) {
result.push_back(
{DocumentUri::FromPath(include.resolved_path).raw_uri});
{DocumentUri::fromPath(include.resolved_path).raw_uri});
range = {{0, 0}, {0, 0}};
break;
}
@ -88,7 +90,7 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
if (!range) {
Position position = param.position;
const std::string &buffer = wf->buffer_content;
std::string_view query = LexIdentifierAroundPos(position, buffer);
std::string_view query = lexIdentifierAroundPos(position, buffer);
std::string_view short_query = query;
{
auto pos = query.rfind(':');
@ -103,13 +105,13 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
SymbolIdx best_sym;
best_sym.kind = Kind::Invalid;
auto fn = [&](SymbolIdx sym) {
std::string_view short_name = db->GetSymbolName(sym, false),
std::string_view short_name = db->getSymbolName(sym, false),
name = short_query.size() < query.size()
? db->GetSymbolName(sym, true)
? db->getSymbolName(sym, true)
: short_name;
if (short_name != short_query)
return;
if (Maybe<DeclRef> dr = GetDefinitionSpell(db, sym)) {
if (Maybe<DeclRef> dr = getDefinitionSpell(db, sym)) {
std::tuple<int, int, bool, int> score{
int(name.size() - short_query.size()), 0, dr->file_id != file_id,
std::abs(dr->range.start.line - position.line)};
@ -135,46 +137,46 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
fn({var.usr, Kind::Var});
if (best_sym.kind != Kind::Invalid) {
Maybe<DeclRef> dr = GetDefinitionSpell(db, best_sym);
Maybe<DeclRef> dr = getDefinitionSpell(db, best_sym);
assert(dr);
if (auto loc = GetLocationLink(db, wfiles, *dr))
if (auto loc = getLocationLink(db, wfiles, *dr))
result.push_back(loc);
}
}
}
reply.ReplyLocationLink(result);
reply.replyLocationLink(result);
}
void MessageHandler::textDocument_typeDefinition(
TextDocumentPositionParam &param, ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!file)
return;
std::vector<LocationLink> result;
auto Add = [&](const QueryType &type) {
auto add = [&](const QueryType &type) {
for (const auto &def : type.def)
if (def.spell)
if (auto loc = GetLocationLink(db, wfiles, *def.spell))
if (auto loc = getLocationLink(db, wfiles, *def.spell))
result.push_back(loc);
if (result.empty())
for (const DeclRef &dr : type.declarations)
if (auto loc = GetLocationLink(db, wfiles, dr))
if (auto loc = getLocationLink(db, wfiles, dr))
result.push_back(loc);
};
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
switch (sym.kind) {
case Kind::Var: {
const QueryVar::Def *def = db->GetVar(sym).AnyDef();
const QueryVar::Def *def = db->getVar(sym).anyDef();
if (def && def->type)
Add(db->Type(def->type));
add(db->getType(def->type));
break;
}
case Kind::Type: {
for (auto &def : db->GetType(sym).def)
for (auto &def : db->getType(sym).def)
if (def.alias_of) {
Add(db->Type(def.alias_of));
add(db->getType(def.alias_of));
break;
}
break;
@ -184,6 +186,6 @@ void MessageHandler::textDocument_typeDefinition(
}
}
reply.ReplyLocationLink(result);
reply.replyLocationLink(result);
}
} // namespace ccls

View File

@ -10,51 +10,51 @@
namespace ccls {
void MessageHandler::textDocument_didChange(TextDocumentDidChangeParam &param) {
std::string path = param.textDocument.uri.GetPath();
wfiles->OnChange(param);
std::string path = param.textDocument.uri.getPath();
wfiles->onChange(param);
if (g_config->index.onChange)
pipeline::Index(path, {}, IndexMode::OnChange, true);
manager->OnView(path);
pipeline::index(path, {}, IndexMode::OnChange, true);
manager->onView(path);
if (g_config->diagnostics.onChange >= 0)
manager->ScheduleDiag(path, g_config->diagnostics.onChange);
manager->scheduleDiag(path, g_config->diagnostics.onChange);
}
void MessageHandler::textDocument_didClose(TextDocumentParam &param) {
std::string path = param.textDocument.uri.GetPath();
wfiles->OnClose(path);
manager->OnClose(path);
pipeline::RemoveCache(path);
std::string path = param.textDocument.uri.getPath();
wfiles->onClose(path);
manager->onClose(path);
pipeline::removeCache(path);
}
void MessageHandler::textDocument_didOpen(DidOpenTextDocumentParam &param) {
std::string path = param.textDocument.uri.GetPath();
WorkingFile *wf = wfiles->OnOpen(param.textDocument);
std::string path = param.textDocument.uri.getPath();
WorkingFile *wf = wfiles->onOpen(param.textDocument);
if (std::optional<std::string> cached_file_contents =
pipeline::LoadIndexedContent(path))
wf->SetIndexContent(*cached_file_contents);
pipeline::loadIndexedContent(path))
wf->setIndexContent(*cached_file_contents);
QueryFile *file = FindFile(path);
QueryFile *file = findFile(path);
if (file) {
EmitSkippedRanges(wf, *file);
EmitSemanticHighlight(db, wf, *file);
emitSkippedRanges(wf, *file);
emitSemanticHighlight(db, wf, *file);
}
include_complete->AddFile(wf->filename);
include_complete->addFile(wf->filename);
// Submit new index request if it is not a header file or there is no
// pending index request.
auto [lang, header] = lookupExtension(path);
if ((lang != LanguageId::Unknown && !header) ||
!pipeline::pending_index_requests)
pipeline::Index(path, {}, IndexMode::Normal, false);
pipeline::index(path, {}, IndexMode::Normal, false);
if (header)
project->IndexRelated(path);
project->indexRelated(path);
manager->OnView(path);
manager->onView(path);
}
void MessageHandler::textDocument_didSave(TextDocumentParam &param) {
const std::string &path = param.textDocument.uri.GetPath();
pipeline::Index(path, {}, IndexMode::Normal, false);
manager->OnSave(path);
const std::string &path = param.textDocument.uri.getPath();
pipeline::index(path, {}, IndexMode::Normal, false);
manager->onSave(path);
}
} // namespace ccls

View File

@ -32,13 +32,14 @@ REFLECT_STRUCT(DocumentHighlight, range, kind, role);
void MessageHandler::textDocument_documentHighlight(
TextDocumentPositionParam &param, ReplyOnce &reply) {
int file_id;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
auto [file, wf] =
findOrFail(param.textDocument.uri.getPath(), reply, &file_id);
if (!wf)
return;
std::vector<DocumentHighlight> result;
std::vector<SymbolRef> syms =
FindSymbolsAtLocation(wf, file, param.position, true);
findSymbolsAtLocation(wf, file, param.position, true);
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0)
continue;
@ -48,7 +49,7 @@ void MessageHandler::textDocument_documentHighlight(
return usr == sym1.usr && kind == sym1.kind;
}))
continue;
if (auto loc = GetLsLocation(db, wfiles, sym, file_id)) {
if (auto loc = getLsLocation(db, wfiles, sym, file_id)) {
DocumentHighlight highlight;
highlight.range = loc->range;
if (sym.role & Role::Write)
@ -75,7 +76,7 @@ REFLECT_STRUCT(DocumentLink, range, target);
void MessageHandler::textDocument_documentLink(TextDocumentParam &param,
ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
@ -83,12 +84,12 @@ void MessageHandler::textDocument_documentLink(TextDocumentParam &param,
int column;
for (const IndexInclude &include : file->def->includes)
if (std::optional<int> bline =
wf->GetBufferPosFromIndexPos(include.line, &column, false)) {
wf->getBufferPosFromIndexPos(include.line, &column, false)) {
const std::string &line = wf->buffer_lines[*bline];
auto start = line.find_first_of("\"<"), end = line.find_last_of("\">");
if (start < end)
result.push_back({lsRange{{*bline, (int)start + 1}, {*bline, (int)end}},
DocumentUri::FromPath(include.resolved_path)});
DocumentUri::fromPath(include.resolved_path)});
}
reply(result);
} // namespace ccls
@ -113,58 +114,52 @@ struct DocumentSymbol {
lsRange selectionRange;
std::vector<std::unique_ptr<DocumentSymbol>> children;
};
void Reflect(JsonWriter &vis, std::unique_ptr<DocumentSymbol> &v);
void reflect(JsonWriter &vis, std::unique_ptr<DocumentSymbol> &v);
REFLECT_STRUCT(DocumentSymbol, name, detail, kind, range, selectionRange,
children);
void Reflect(JsonWriter &vis, std::unique_ptr<DocumentSymbol> &v) {
Reflect(vis, *v);
void reflect(JsonWriter &vis, std::unique_ptr<DocumentSymbol> &v) {
reflect(vis, *v);
}
template <typename Def>
bool Ignore(const Def *def) {
return false;
}
template <>
bool Ignore(const QueryType::Def *def) {
template <typename Def> bool ignore(const Def *def) { return false; }
template <> bool ignore(const QueryType::Def *def) {
return !def || def->kind == SymbolKind::TypeParameter;
}
template<>
bool Ignore(const QueryVar::Def *def) {
template <> bool ignore(const QueryVar::Def *def) {
return !def || def->is_local();
}
void Uniquify(std::vector<std::unique_ptr<DocumentSymbol>> &cs) {
void uniquify(std::vector<std::unique_ptr<DocumentSymbol>> &cs) {
std::sort(cs.begin(), cs.end(),
[](auto &l, auto &r) { return l->range < r->range; });
cs.erase(std::unique(cs.begin(), cs.end(),
[](auto &l, auto &r) { return l->range == r->range; }),
cs.end());
for (auto &c : cs)
Uniquify(c->children);
uniquify(c->children);
}
} // namespace
void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
ReplyOnce &reply) {
DocumentSymbolParam param;
Reflect(reader, param);
reflect(reader, param);
int file_id;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
auto [file, wf] =
findOrFail(param.textDocument.uri.getPath(), reply, &file_id);
if (!wf)
return;
auto Allows = [&](SymbolRef sym) {
return !(sym.role & param.excludeRole);
};
auto allows = [&](SymbolRef sym) { return !(sym.role & param.excludeRole); };
if (param.startLine >= 0) {
std::vector<lsRange> result;
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0 || !Allows(sym) ||
if (refcnt <= 0 || !allows(sym) ||
!(param.startLine <= sym.range.start.line &&
sym.range.start.line <= param.endLine))
continue;
if (auto loc = GetLsLocation(db, wfiles, sym, file_id))
if (auto loc = getLsLocation(db, wfiles, sym, file_id))
result.push_back(loc->range);
}
std::sort(result.begin(), result.end());
@ -174,22 +169,22 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
std::vector<std::pair<std::vector<const void *>, DocumentSymbol *>> funcs,
types;
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0 || !sym.extent.Valid())
if (refcnt <= 0 || !sym.extent.valid())
continue;
auto r = sym2ds.try_emplace(SymbolIdx{sym.usr, sym.kind});
auto &ds = r.first->second;
if (!ds || sym.role & Role::Definition) {
if (!ds)
ds = std::make_unique<DocumentSymbol>();
if (auto range = GetLsRange(wf, sym.range)) {
if (auto range = getLsRange(wf, sym.range)) {
ds->selectionRange = *range;
ds->range = ds->selectionRange;
// For a macro expansion, M(name), we may use `M` for extent and
// `name` for spell, do the check as selectionRange must be a subrange
// of range.
if (sym.extent.Valid())
if (auto range1 = GetLsRange(wf, sym.extent);
range1 && range1->Includes(*range))
if (sym.extent.valid())
if (auto range1 = getLsRange(wf, sym.extent);
range1 && range1->includes(*range))
ds->range = *range1;
}
}
@ -197,19 +192,19 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
continue;
std::vector<const void *> def_ptrs;
SymbolKind kind = SymbolKind::Unknown;
WithEntity(db, sym, [&](const auto &entity) {
auto *def = entity.AnyDef();
withEntity(db, sym, [&](const auto &entity) {
auto *def = entity.anyDef();
if (!def)
return;
ds->name = def->Name(false);
ds->name = def->name(false);
ds->detail = def->detailed_name;
for (auto &def : entity.def)
if (def.file_id == file_id && !Ignore(&def)) {
if (def.file_id == file_id && !ignore(&def)) {
kind = ds->kind = def.kind;
def_ptrs.push_back(&def);
}
});
if (def_ptrs.empty() || !(kind == SymbolKind::Namespace || Allows(sym))) {
if (def_ptrs.empty() || !(kind == SymbolKind::Namespace || allows(sym))) {
ds.reset();
continue;
}
@ -248,22 +243,22 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
std::vector<std::unique_ptr<DocumentSymbol>> result;
for (auto &[_, ds] : sym2ds)
if (ds) {
Uniquify(ds->children);
uniquify(ds->children);
result.push_back(std::move(ds));
}
Uniquify(result);
uniquify(result);
reply(result);
} else {
std::vector<SymbolInformation> result;
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0 || !Allows(sym))
if (refcnt <= 0 || !allows(sym))
continue;
if (std::optional<SymbolInformation> info =
GetSymbolInfo(db, sym, false)) {
if ((sym.kind == Kind::Type && Ignore(db->GetType(sym).AnyDef())) ||
(sym.kind == Kind::Var && Ignore(db->GetVar(sym).AnyDef())))
getSymbolInfo(db, sym, false)) {
if ((sym.kind == Kind::Type && ignore(db->getType(sym).anyDef())) ||
(sym.kind == Kind::Var && ignore(db->getVar(sym).anyDef())))
continue;
if (auto loc = GetLsLocation(db, wfiles, sym, file_id)) {
if (auto loc = getLsLocation(db, wfiles, sym, file_id)) {
info->location = *loc;
result.push_back(*info);
}

View File

@ -19,16 +19,16 @@ REFLECT_STRUCT(FoldingRange, startLine, startCharacter, endLine, endCharacter,
void MessageHandler::textDocument_foldingRange(TextDocumentParam &param,
ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
std::vector<FoldingRange> result;
std::optional<lsRange> ls_range;
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.extent.Valid() &&
if (refcnt > 0 && sym.extent.valid() &&
(sym.kind == Kind::Func || sym.kind == Kind::Type) &&
(ls_range = GetLsRange(wf, sym.extent))) {
(ls_range = getLsRange(wf, sym.extent))) {
FoldingRange &fold = result.emplace_back();
fold.startLine = ls_range->start.line;
fold.startCharacter = ls_range->start.character;

View File

@ -12,25 +12,24 @@ namespace ccls {
using namespace clang;
namespace {
llvm::Expected<tooling::Replacements>
FormatCode(std::string_view code, std::string_view file, tooling::Range Range) {
StringRef Code(code.data(), code.size()), File(file.data(), file.size());
auto Style = format::getStyle("file", File, "LLVM", Code, nullptr);
if (!Style)
return Style.takeError();
tooling::Replacements IncludeReplaces =
format::sortIncludes(*Style, Code, {Range}, File);
auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
if (!Changed)
return Changed.takeError();
return IncludeReplaces.merge(format::reformat(
*Style, *Changed,
tooling::calculateRangesAfterReplacements(IncludeReplaces, {Range}),
File));
llvm::Expected<tooling::Replacements> formatCode(StringRef code, StringRef file,
tooling::Range range) {
auto style = format::getStyle("file", file, "LLVM", code, nullptr);
if (!style)
return style.takeError();
tooling::Replacements includeReplaces =
format::sortIncludes(*style, code, {range}, file);
auto changed = tooling::applyAllReplacements(code, includeReplaces);
if (!changed)
return changed.takeError();
return includeReplaces.merge(format::reformat(
*style, *changed,
tooling::calculateRangesAfterReplacements(includeReplaces, {range}),
file));
}
std::vector<TextEdit> ReplacementsToEdits(std::string_view code,
const tooling::Replacements &Repls) {
std::vector<TextEdit> replacementsToEdits(std::string_view code,
const tooling::Replacements &repls) {
std::vector<TextEdit> ret;
int i = 0, line = 0, col = 0;
auto move = [&](int p) {
@ -46,57 +45,59 @@ std::vector<TextEdit> ReplacementsToEdits(std::string_view code,
col++;
}
};
for (const auto &R : Repls) {
move(R.getOffset());
for (const auto &r : repls) {
move(r.getOffset());
int l = line, c = col;
move(R.getOffset() + R.getLength());
ret.push_back({{{l, c}, {line, col}}, R.getReplacementText().str()});
move(r.getOffset() + r.getLength());
ret.push_back({{{l, c}, {line, col}}, r.getReplacementText().str()});
}
return ret;
}
void Format(ReplyOnce &reply, WorkingFile *wfile, tooling::Range range) {
void format(ReplyOnce &reply, WorkingFile *wfile, tooling::Range range) {
std::string_view code = wfile->buffer_content;
auto ReplsOrErr = FormatCode(code, wfile->filename, range);
if (ReplsOrErr)
reply(ReplacementsToEdits(code, *ReplsOrErr));
auto replsOrErr = formatCode(
StringRef(code.data(), code.size()),
StringRef(wfile->filename.data(), wfile->filename.size()), range);
if (replsOrErr)
reply(replacementsToEdits(code, *replsOrErr));
else
reply.Error(ErrorCode::UnknownErrorCode,
llvm::toString(ReplsOrErr.takeError()));
reply.error(ErrorCode::UnknownErrorCode,
llvm::toString(replsOrErr.takeError()));
}
} // namespace
void MessageHandler::textDocument_formatting(DocumentFormattingParam &param,
ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
Format(reply, wf, {0, (unsigned)wf->buffer_content.size()});
format(reply, wf, {0, (unsigned)wf->buffer_content.size()});
}
void MessageHandler::textDocument_onTypeFormatting(
DocumentOnTypeFormattingParam &param, ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf) {
return;
}
std::string_view code = wf->buffer_content;
int pos = GetOffsetForPosition(param.position, code);
int pos = getOffsetForPosition(param.position, code);
auto lbrace = code.find_last_of('{', pos);
if (lbrace == std::string::npos)
lbrace = pos;
Format(reply, wf, {(unsigned)lbrace, unsigned(pos - lbrace)});
format(reply, wf, {(unsigned)lbrace, unsigned(pos - lbrace)});
}
void MessageHandler::textDocument_rangeFormatting(
DocumentRangeFormattingParam &param, ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf) {
return;
}
std::string_view code = wf->buffer_content;
int begin = GetOffsetForPosition(param.range.start, code),
end = GetOffsetForPosition(param.range.end, code);
Format(reply, wf, {(unsigned)begin, unsigned(end - begin)});
int begin = getOffsetForPosition(param.range.start, code),
end = getOffsetForPosition(param.range.end, code);
format(reply, wf, {(unsigned)begin, unsigned(end - begin)});
}
} // namespace ccls

View File

@ -15,21 +15,21 @@ struct Hover {
std::optional<lsRange> range;
};
void Reflect(JsonWriter &vis, MarkedString &v) {
void reflect(JsonWriter &vis, MarkedString &v) {
// If there is a language, emit a `{language:string, value:string}` object. If
// not, emit a string.
if (v.language) {
vis.StartObject();
vis.startObject();
REFLECT_MEMBER(language);
REFLECT_MEMBER(value);
vis.EndObject();
vis.endObject();
} else {
Reflect(vis, v.value);
reflect(vis, v.value);
}
}
REFLECT_STRUCT(Hover, contents, range);
const char *LanguageIdentifier(LanguageId lang) {
const char *languageIdentifier(LanguageId lang) {
switch (lang) {
// clang-format off
case LanguageId::C: return "c";
@ -43,10 +43,10 @@ const char *LanguageIdentifier(LanguageId lang) {
// Returns the hover or detailed name for `sym`, if any.
std::pair<std::optional<MarkedString>, std::optional<MarkedString>>
GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
getHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
const char *comments = nullptr;
std::optional<MarkedString> ls_comments, hover;
WithEntity(db, sym, [&](const auto &entity) {
withEntity(db, sym, [&](const auto &entity) {
for (auto &d : entity.def) {
if (!comments && d.comments[0])
comments = d.comments;
@ -57,7 +57,7 @@ GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
d.hover[0] ? d.hover
: d.detailed_name[0] ? d.detailed_name : nullptr) {
if (!hover)
hover = {LanguageIdentifier(lang), s};
hover = {languageIdentifier(lang), s};
else if (strlen(s) > hover->value.size())
hover->value = s;
}
@ -67,7 +67,7 @@ GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
}
if (!hover && entity.def.size()) {
auto &d = entity.def[0];
hover = {LanguageIdentifier(lang)};
hover = {languageIdentifier(lang)};
if (d.hover[0])
hover->value = d.hover;
else if (d.detailed_name[0])
@ -82,18 +82,18 @@ GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
void MessageHandler::textDocument_hover(TextDocumentPositionParam &param,
ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
Hover result;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
std::optional<lsRange> ls_range =
GetLsRange(wfiles->GetFile(file->def->path), sym.range);
getLsRange(wfiles->getFile(file->def->path), sym.range);
if (!ls_range)
continue;
auto [hover, comments] = GetHover(db, file->def->language, sym, file->id);
auto [hover, comments] = getHover(db, file->def->language, sym, file->id);
if (comments || hover) {
result.range = *ls_range;
if (comments)

View File

@ -36,20 +36,20 @@ REFLECT_STRUCT(ReferenceParam, textDocument, position, context, folders, base,
void MessageHandler::textDocument_references(JsonReader &reader,
ReplyOnce &reply) {
ReferenceParam param;
Reflect(reader, param);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
reflect(reader, param);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
for (auto &folder : param.folders)
EnsureEndsInSlash(folder);
std::vector<uint8_t> file_set = db->GetFileSet(param.folders);
ensureEndsInSlash(folder);
std::vector<uint8_t> file_set = db->getFileSet(param.folders);
std::vector<Location> result;
std::unordered_set<Use> seen_uses;
int line = param.position.line;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
// Found symbol. Return references.
std::unordered_set<Usr> seen;
seen.insert(sym.usr);
@ -63,14 +63,14 @@ void MessageHandler::textDocument_references(JsonReader &reader,
if (file_set[use.file_id] &&
Role(use.role & param.role) == param.role &&
!(use.role & param.excludeRole) && seen_uses.insert(use).second)
if (auto loc = GetLsLocation(db, wfiles, use))
if (auto loc = getLsLocation(db, wfiles, use))
result.push_back(*loc);
};
WithEntity(db, sym, [&](const auto &entity) {
withEntity(db, sym, [&](const auto &entity) {
SymbolKind parent_kind = SymbolKind::Unknown;
for (auto &def : entity.def)
if (def.spell) {
parent_kind = GetSymbolKind(db, sym);
parent_kind = getSymbolKind(db, sym);
if (param.base)
for (Usr usr : make_range(def.bases_begin(), def.bases_end()))
if (!seen.count(usr)) {
@ -112,7 +112,7 @@ void MessageHandler::textDocument_references(JsonReader &reader,
if (include.resolved_path == path) {
// Another file |file1| has the same include line.
Location &loc = result.emplace_back();
loc.uri = DocumentUri::FromPath(file1.def->path);
loc.uri = DocumentUri::fromPath(file1.def->path);
loc.range.start.line = loc.range.end.line = include.line;
break;
}

View File

@ -12,18 +12,18 @@ using namespace clang;
namespace ccls {
namespace {
WorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *wfiles, SymbolRef sym,
WorkspaceEdit buildWorkspaceEdit(DB *db, WorkingFiles *wfiles, SymbolRef sym,
std::string_view old_text,
const std::string &new_text) {
std::unordered_map<int, std::pair<WorkingFile *, TextDocumentEdit>> path2edit;
std::unordered_map<int, std::unordered_set<Range>> edited;
EachOccurrence(db, sym, true, [&](Use use) {
eachOccurrence(db, sym, true, [&](Use use) {
int file_id = use.file_id;
QueryFile &file = db->files[file_id];
if (!file.def || !edited[file_id].insert(use.range).second)
return;
std::optional<Location> loc = GetLsLocation(db, wfiles, use);
std::optional<Location> loc = getLsLocation(db, wfiles, use);
if (!loc)
return;
@ -31,14 +31,14 @@ WorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *wfiles, SymbolRef sym,
auto &edit = it->second.second;
if (inserted) {
const std::string &path = file.def->path;
edit.textDocument.uri = DocumentUri::FromPath(path);
if ((it->second.first = wfiles->GetFile(path)))
edit.textDocument.uri = DocumentUri::fromPath(path);
if ((it->second.first = wfiles->getFile(path)))
edit.textDocument.version = it->second.first->version;
}
// TODO LoadIndexedContent if wf is nullptr.
if (WorkingFile *wf = it->second.first) {
int start = GetOffsetForPosition(loc->range.start, wf->buffer_content),
end = GetOffsetForPosition(loc->range.end, wf->buffer_content);
int start = getOffsetForPosition(loc->range.start, wf->buffer_content),
end = getOffsetForPosition(loc->range.end, wf->buffer_content);
if (wf->buffer_content.compare(start, end - start, old_text))
return;
}
@ -53,15 +53,15 @@ WorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *wfiles, SymbolRef sym,
} // namespace
void MessageHandler::textDocument_rename(RenameParam &param, ReplyOnce &reply) {
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
auto [file, wf] = findOrFail(param.textDocument.uri.getPath(), reply);
if (!wf)
return;
WorkspaceEdit result;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
result = BuildWorkspaceEdit(
for (SymbolRef sym : findSymbolsAtLocation(wf, file, param.position)) {
result = buildWorkspaceEdit(
db, wfiles, sym,
LexIdentifierAroundPos(param.position, wf->buffer_content),
lexIdentifierAroundPos(param.position, wf->buffer_content),
param.newName);
break;
}

View File

@ -28,12 +28,12 @@ REFLECT_STRUCT(ParameterInformation, label);
REFLECT_STRUCT(SignatureInformation, label, documentation, parameters);
REFLECT_STRUCT(SignatureHelp, signatures, activeSignature, activeParameter);
void BuildOptional(const CodeCompletionString &CCS, std::string &label,
void buildOptional(const CodeCompletionString &ccs, std::string &label,
std::vector<ParameterInformation> &ls_params) {
for (const auto &Chunk : CCS) {
switch (Chunk.Kind) {
for (const auto &chunk : ccs) {
switch (chunk.Kind) {
case CodeCompletionString::CK_Optional:
BuildOptional(*Chunk.Optional, label, ls_params);
buildOptional(*chunk.Optional, label, ls_params);
break;
case CodeCompletionString::CK_Placeholder:
// A string that acts as a placeholder for, e.g., a function call
@ -44,79 +44,81 @@ void BuildOptional(const CodeCompletionString &CCS, std::string &label,
// the code-completion location within a function call, message send,
// macro invocation, etc.
int off = (int)label.size();
label += Chunk.Text;
label += chunk.Text;
ls_params.push_back({{off, (int)label.size()}});
break;
}
case CodeCompletionString::CK_VerticalSpace:
break;
default:
label += Chunk.Text;
label += chunk.Text;
break;
}
}
}
class SignatureHelpConsumer : public CodeCompleteConsumer {
std::shared_ptr<GlobalCodeCompletionAllocator> Alloc;
CodeCompletionTUInfo CCTUInfo;
std::shared_ptr<GlobalCodeCompletionAllocator> alloc;
CodeCompletionTUInfo cCTUInfo;
public:
bool from_cache;
SignatureHelp ls_sighelp;
SignatureHelpConsumer(const clang::CodeCompleteOptions &Opts,
bool from_cache)
SignatureHelpConsumer(const clang::CodeCompleteOptions &opts, bool from_cache)
:
#if LLVM_VERSION_MAJOR >= 9 // rC358696
CodeCompleteConsumer(Opts),
CodeCompleteConsumer(opts),
#else
CodeCompleteConsumer(Opts, false),
CodeCompleteConsumer(opts, false),
#endif
Alloc(std::make_shared<GlobalCodeCompletionAllocator>()),
CCTUInfo(Alloc), from_cache(from_cache) {}
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
unsigned NumCandidates
alloc(std::make_shared<GlobalCodeCompletionAllocator>()),
cCTUInfo(alloc), from_cache(from_cache) {
}
void ProcessOverloadCandidates(Sema &s, unsigned currentArg,
OverloadCandidate *candidates,
unsigned numCandidates
#if LLVM_VERSION_MAJOR >= 8
,
SourceLocation OpenParLoc
SourceLocation openParLoc
#endif
) override {
ls_sighelp.activeParameter = (int)CurrentArg;
for (unsigned i = 0; i < NumCandidates; i++) {
OverloadCandidate Cand = Candidates[i];
ls_sighelp.activeParameter = (int)currentArg;
for (unsigned i = 0; i < numCandidates; i++) {
OverloadCandidate cand = candidates[i];
// We want to avoid showing instantiated signatures, because they may be
// long in some cases (e.g. when 'T' is substituted with 'std::string', we
// would get 'std::basic_string<char>').
if (auto *Func = Cand.getFunction())
if (auto *Pattern = Func->getTemplateInstantiationPattern())
Cand = OverloadCandidate(Pattern);
if (auto *func = cand.getFunction())
if (auto *pattern = func->getTemplateInstantiationPattern())
cand = OverloadCandidate(pattern);
const auto *CCS =
Cand.CreateSignatureString(CurrentArg, S, *Alloc, CCTUInfo, true);
const auto *ccs =
cand.CreateSignatureString(currentArg, s, *alloc, cCTUInfo, true);
const char *ret_type = nullptr;
SignatureInformation &ls_sig = ls_sighelp.signatures.emplace_back();
const RawComment *RC = getCompletionComment(S.getASTContext(), Cand.getFunction());
ls_sig.documentation = RC ? RC->getBriefText(S.getASTContext()) : "";
for (const auto &Chunk : *CCS)
switch (Chunk.Kind) {
const RawComment *rc =
getCompletionComment(s.getASTContext(), cand.getFunction());
ls_sig.documentation = rc ? rc->getBriefText(s.getASTContext()) : "";
for (const auto &chunk : *ccs)
switch (chunk.Kind) {
case CodeCompletionString::CK_ResultType:
ret_type = Chunk.Text;
ret_type = chunk.Text;
break;
case CodeCompletionString::CK_Placeholder:
case CodeCompletionString::CK_CurrentParameter: {
int off = (int)ls_sig.label.size();
ls_sig.label += Chunk.Text;
ls_sig.label += chunk.Text;
ls_sig.parameters.push_back({{off, (int)ls_sig.label.size()}});
break;
}
case CodeCompletionString::CK_Optional:
BuildOptional(*Chunk.Optional, ls_sig.label, ls_sig.parameters);
buildOptional(*chunk.Optional, ls_sig.label, ls_sig.parameters);
break;
case CodeCompletionString::CK_VerticalSpace:
break;
default:
ls_sig.label += Chunk.Text;
ls_sig.label += chunk.Text;
break;
}
if (ret_type) {
@ -124,8 +126,7 @@ public:
ls_sig.label += ret_type;
}
}
std::sort(
ls_sighelp.signatures.begin(), ls_sighelp.signatures.end(),
std::sort(ls_sighelp.signatures.begin(), ls_sighelp.signatures.end(),
[](const SignatureInformation &l, const SignatureInformation &r) {
if (l.parameters.size() != r.parameters.size())
return l.parameters.size() < r.parameters.size();
@ -135,8 +136,8 @@ public:
});
}
CodeCompletionAllocator &getAllocator() override { return *Alloc; }
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
CodeCompletionAllocator &getAllocator() override { return *alloc; }
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return cCTUInfo; }
};
} // namespace
@ -144,45 +145,45 @@ void MessageHandler::textDocument_signatureHelp(
TextDocumentPositionParam &param, ReplyOnce &reply) {
static CompleteConsumerCache<SignatureHelp> cache;
Position begin_pos = param.position;
std::string path = param.textDocument.uri.GetPath();
WorkingFile *wf = wfiles->GetFile(path);
std::string path = param.textDocument.uri.getPath();
WorkingFile *wf = wfiles->getFile(path);
if (!wf) {
reply.NotOpened(path);
reply.notOpened(path);
return;
}
{
std::string filter;
Position end_pos;
begin_pos = wf->GetCompletionPosition(param.position, &filter, &end_pos);
begin_pos = wf->getCompletionPosition(param.position, &filter, &end_pos);
}
SemaManager::OnComplete callback =
[reply, path, begin_pos](CodeCompleteConsumer *OptConsumer) {
if (!OptConsumer)
[reply, path, begin_pos](CodeCompleteConsumer *optConsumer) {
if (!optConsumer)
return;
auto *Consumer = static_cast<SignatureHelpConsumer *>(OptConsumer);
reply(Consumer->ls_sighelp);
if (!Consumer->from_cache) {
cache.WithLock([&]() {
auto *consumer = static_cast<SignatureHelpConsumer *>(optConsumer);
reply(consumer->ls_sighelp);
if (!consumer->from_cache) {
cache.withLock([&]() {
cache.path = path;
cache.position = begin_pos;
cache.result = Consumer->ls_sighelp;
cache.result = consumer->ls_sighelp;
});
}
};
CodeCompleteOptions CCOpts;
CCOpts.IncludeGlobals = false;
CCOpts.IncludeMacros = false;
CCOpts.IncludeBriefComments = true;
if (cache.IsCacheValid(path, begin_pos)) {
SignatureHelpConsumer Consumer(CCOpts, true);
cache.WithLock([&]() { Consumer.ls_sighelp = cache.result; });
callback(&Consumer);
CodeCompleteOptions ccOpts;
ccOpts.IncludeGlobals = false;
ccOpts.IncludeMacros = false;
ccOpts.IncludeBriefComments = true;
if (cache.isCacheValid(path, begin_pos)) {
SignatureHelpConsumer consumer(ccOpts, true);
cache.withLock([&]() { consumer.ls_sighelp = cache.result; });
callback(&consumer);
} else {
manager->comp_tasks.PushBack(std::make_unique<SemaManager::CompTask>(
reply.id, param.textDocument.uri.GetPath(), param.position,
std::make_unique<SignatureHelpConsumer>(CCOpts, false), CCOpts,
manager->comp_tasks.pushBack(std::make_unique<SemaManager::CompTask>(
reply.id, param.textDocument.uri.getPath(), param.position,
std::make_unique<SignatureHelpConsumer>(ccOpts, false), ccOpts,
callback));
}
}

View File

@ -1,13 +1,13 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "sema_manager.hh"
#include "fuzzy_match.hh"
#include "log.hh"
#include "message_handler.hh"
#include "pipeline.hh"
#include "project.hh"
#include "query.hh"
#include "sema_manager.hh"
#include <llvm/ADT/STLExtras.h>
#include <llvm/ADT/StringRef.h>
@ -24,16 +24,16 @@ REFLECT_STRUCT(SymbolInformation, name, kind, location, containerName);
void MessageHandler::workspace_didChangeConfiguration(EmptyParam &) {
for (auto &[folder, _] : g_config->workspaceFolders)
project->Load(folder);
project->Index(wfiles, RequestId());
project->load(folder);
project->index(wfiles, RequestId());
manager->Clear();
manager->clear();
};
void MessageHandler::workspace_didChangeWatchedFiles(
DidChangeWatchedFilesParam &param) {
for (auto &event : param.changes) {
std::string path = event.uri.GetPath();
std::string path = event.uri.getPath();
if ((g_config->cache.directory.size() &&
StringRef(path).startswith(g_config->cache.directory)) ||
lookupExtension(path).first == LanguageId::Unknown)
@ -46,19 +46,19 @@ void MessageHandler::workspace_didChangeWatchedFiles(
case FileChangeType::Created:
case FileChangeType::Changed: {
IndexMode mode =
wfiles->GetFile(path) ? IndexMode::Normal : IndexMode::Background;
pipeline::Index(path, {}, mode, true);
wfiles->getFile(path) ? IndexMode::Normal : IndexMode::Background;
pipeline::index(path, {}, mode, true);
if (event.type == FileChangeType::Changed) {
if (mode == IndexMode::Normal)
manager->OnSave(path);
manager->onSave(path);
else
manager->OnClose(path);
manager->onClose(path);
}
break;
}
case FileChangeType::Deleted:
pipeline::Index(path, {}, IndexMode::Delete, false);
manager->OnClose(path);
pipeline::index(path, {}, IndexMode::Delete, false);
manager->onClose(path);
break;
}
}
@ -67,8 +67,8 @@ void MessageHandler::workspace_didChangeWatchedFiles(
void MessageHandler::workspace_didChangeWorkspaceFolders(
DidChangeWorkspaceFoldersParam &param) {
for (const WorkspaceFolder &wf : param.event.removed) {
std::string root = wf.uri.GetPath();
EnsureEndsInSlash(root);
std::string root = wf.uri.getPath();
ensureEndsInSlash(root);
LOG_S(INFO) << "delete workspace folder " << wf.name << ": " << root;
auto it = llvm::find_if(g_config->workspaceFolders,
[&](auto &folder) { return folder.first == root; });
@ -83,9 +83,9 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
}
auto &workspaceFolders = g_config->workspaceFolders;
for (const WorkspaceFolder &wf : param.event.added) {
std::string folder = wf.uri.GetPath();
EnsureEndsInSlash(folder);
std::string real = RealPath(folder) + '/';
std::string folder = wf.uri.getPath();
ensureEndsInSlash(folder);
std::string real = realPath(folder) + '/';
if (folder == real)
real.clear();
LOG_S(INFO) << "add workspace folder " << wf.name << ": "
@ -95,27 +95,27 @@ void MessageHandler::workspace_didChangeWorkspaceFolders(
for (; it != workspaceFolders.begin() && folder < it[-1].first; --it)
*it = it[-1];
*it = {folder, real};
project->Load(folder);
project->load(folder);
}
project->Index(wfiles, RequestId());
project->index(wfiles, RequestId());
manager->Clear();
manager->clear();
}
namespace {
// Lookup |symbol| in |db| and insert the value into |result|.
bool AddSymbol(
bool addSymbol(
DB *db, WorkingFiles *wfiles, const std::vector<uint8_t> &file_set,
SymbolIdx sym, bool use_detailed,
std::vector<std::tuple<SymbolInformation, int, SymbolIdx>> *result) {
std::optional<SymbolInformation> info = GetSymbolInfo(db, sym, true);
std::optional<SymbolInformation> info = getSymbolInfo(db, sym, true);
if (!info)
return false;
Maybe<DeclRef> dr;
bool in_folder = false;
WithEntity(db, sym, [&](const auto &entity) {
withEntity(db, sym, [&](const auto &entity) {
for (auto &def : entity.def)
if (def.spell) {
dr = def.spell;
@ -124,7 +124,7 @@ bool AddSymbol(
}
});
if (!dr) {
auto &decls = GetNonDefDeclarations(db, sym);
auto &decls = getNonDefDeclarations(db, sym);
for (auto &dr1 : decls) {
dr = dr1;
if (!in_folder && (in_folder = file_set[dr1.file_id]))
@ -134,7 +134,7 @@ bool AddSymbol(
if (!in_folder)
return false;
std::optional<Location> ls_location = GetLsLocation(db, wfiles, *dr);
std::optional<Location> ls_location = getLsLocation(db, wfiles, *dr);
if (!ls_location)
return false;
info->location = *ls_location;
@ -148,8 +148,8 @@ void MessageHandler::workspace_symbol(WorkspaceSymbolParam &param,
std::vector<SymbolInformation> result;
const std::string &query = param.query;
for (auto &folder : param.folders)
EnsureEndsInSlash(folder);
std::vector<uint8_t> file_set = db->GetFileSet(param.folders);
ensureEndsInSlash(folder);
std::vector<uint8_t> file_set = db->getFileSet(param.folders);
// {symbol info, matching detailed_name or short_name, index}
std::vector<std::tuple<SymbolInformation, int, SymbolIdx>> cands;
@ -162,23 +162,23 @@ void MessageHandler::workspace_symbol(WorkspaceSymbolParam &param,
if (!isspace(c))
query_without_space += c;
auto Add = [&](SymbolIdx sym) {
std::string_view detailed_name = db->GetSymbolName(sym, true);
int pos = ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
auto add = [&](SymbolIdx sym) {
std::string_view detailed_name = db->getSymbolName(sym, true);
int pos = reverseSubseqMatch(query_without_space, detailed_name, sensitive);
return pos >= 0 &&
AddSymbol(db, wfiles, file_set, sym,
addSymbol(db, wfiles, file_set, sym,
detailed_name.find(':', pos) != std::string::npos,
&cands) &&
cands.size() >= g_config->workspaceSymbol.maxNum;
};
for (auto &func : db->funcs)
if (Add({func.usr, Kind::Func}))
if (add({func.usr, Kind::Func}))
goto done_add;
for (auto &type : db->types)
if (Add({type.usr, Kind::Type}))
if (add({type.usr, Kind::Type}))
goto done_add;
for (auto &var : db->vars)
if (var.def.size() && !var.def[0].is_local() && Add({var.usr, Kind::Var}))
if (var.def.size() && !var.def[0].is_local() && add({var.usr, Kind::Var}))
goto done_add;
done_add:
@ -187,11 +187,11 @@ done_add:
int longest = 0;
for (auto &cand : cands)
longest = std::max(
longest, int(db->GetSymbolName(std::get<2>(cand), true).size()));
longest, int(db->getSymbolName(std::get<2>(cand), true).size()));
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
for (auto &cand : cands)
std::get<1>(cand) = fuzzy.Match(
db->GetSymbolName(std::get<2>(cand), std::get<1>(cand)), false);
std::get<1>(cand) = fuzzy.match(
db->getSymbolName(std::get<2>(cand), std::get<1>(cand)), false);
std::sort(cands.begin(), cands.end(), [](const auto &l, const auto &r) {
return std::get<1>(l) > std::get<1>(r);
});

View File

@ -40,17 +40,17 @@ struct PublishDiagnosticParam {
REFLECT_STRUCT(PublishDiagnosticParam, uri, diagnostics);
} // namespace
void VFS::Clear() {
void VFS::clear() {
std::lock_guard lock(mutex);
state.clear();
}
int VFS::Loaded(const std::string &path) {
int VFS::loaded(const std::string &path) {
std::lock_guard lock(mutex);
return state[path].loaded;
}
bool VFS::Stamp(const std::string &path, int64_t ts, int step) {
bool VFS::stamp(const std::string &path, int64_t ts, int step) {
std::lock_guard<std::mutex> lock(mutex);
State &st = state[path];
if (st.timestamp < ts || (st.timestamp == ts && st.step < step)) {
@ -62,11 +62,11 @@ bool VFS::Stamp(const std::string &path, int64_t ts, int step) {
}
struct MessageHandler;
void StandaloneInitialize(MessageHandler &, const std::string &root);
void standaloneInitialize(MessageHandler &, const std::string &root);
namespace pipeline {
std::atomic<bool> quit;
std::atomic<bool> g_quit;
std::atomic<int64_t> loaded_ts{0}, pending_index_requests{0}, request_id{0};
int64_t tick = 0;
@ -100,7 +100,7 @@ struct InMemoryIndexFile {
std::shared_mutex g_index_mutex;
std::unordered_map<std::string, InMemoryIndexFile> g_index;
bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
bool cacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
const std::vector<const char *> &args,
const std::optional<std::string> &from) {
{
@ -130,7 +130,7 @@ bool CacheInvalid(VFS *vfs, IndexFile *prev, const std::string &path,
return changed >= 0;
};
std::string AppendSerializationFormat(const std::string &base) {
std::string appendSerializationFormat(const std::string &base) {
switch (g_config->cache.format) {
case SerializeFormat::Binary:
return base + ".blob";
@ -139,7 +139,7 @@ std::string AppendSerializationFormat(const std::string &base) {
}
}
std::string GetCachePath(std::string src) {
std::string getCachePath(std::string src) {
if (g_config->cache.hierarchicalPath) {
std::string ret = src[0] == '/' ? src.substr(1) : src;
#ifdef _WIN32
@ -151,16 +151,16 @@ std::string GetCachePath(std::string src) {
if (StringRef(src).startswith(root)) {
auto len = root.size();
return g_config->cache.directory +
EscapeFileName(root.substr(0, len - 1)) + '/' +
EscapeFileName(src.substr(len));
escapeFileName(root.substr(0, len - 1)) + '/' +
escapeFileName(src.substr(len));
}
return g_config->cache.directory + '@' +
EscapeFileName(g_config->fallbackFolder.substr(
escapeFileName(g_config->fallbackFolder.substr(
0, g_config->fallbackFolder.size() - 1)) +
'/' + EscapeFileName(src);
'/' + escapeFileName(src);
}
std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
std::unique_ptr<IndexFile> rawCacheLoad(const std::string &path) {
if (g_config->cache.retainInMemory) {
std::shared_lock lock(g_index_mutex);
auto it = g_index.find(path);
@ -170,27 +170,27 @@ std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
return nullptr;
}
std::string cache_path = GetCachePath(path);
std::optional<std::string> file_content = ReadContent(cache_path);
std::string cache_path = getCachePath(path);
std::optional<std::string> file_content = readContent(cache_path);
std::optional<std::string> serialized_indexed_content =
ReadContent(AppendSerializationFormat(cache_path));
readContent(appendSerializationFormat(cache_path));
if (!file_content || !serialized_indexed_content)
return nullptr;
return ccls::Deserialize(g_config->cache.format, path,
return ccls::deserialize(g_config->cache.format, path,
*serialized_indexed_content, *file_content,
IndexFile::kMajorVersion);
}
std::mutex &GetFileMutex(const std::string &path) {
const int N_MUTEXES = 256;
static std::mutex mutexes[N_MUTEXES];
return mutexes[std::hash<std::string>()(path) % N_MUTEXES];
std::mutex &getFileMutex(const std::string &path) {
const int n_MUTEXES = 256;
static std::mutex mutexes[n_MUTEXES];
return mutexes[std::hash<std::string>()(path) % n_MUTEXES];
}
bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
bool indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
Project *project, VFS *vfs, const GroupMatch &matcher) {
std::optional<IndexRequest> opt_request = index_request->TryPopFront();
std::optional<IndexRequest> opt_request = index_request->tryPopFront();
if (!opt_request)
return false;
auto &request = *opt_request;
@ -203,17 +203,17 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (request.path.empty()) {
IndexUpdate dummy;
dummy.refresh = true;
on_indexed->PushBack(std::move(dummy), false);
on_indexed->pushBack(std::move(dummy), false);
return false;
}
if (!matcher.Matches(request.path)) {
if (!matcher.matches(request.path)) {
LOG_IF_S(INFO, loud) << "skip " << request.path;
return false;
}
Project::Entry entry =
project->FindEntry(request.path, true, request.must_exist);
project->findEntry(request.path, true, request.must_exist);
if (request.must_exist && entry.filename.empty())
return true;
if (request.args.size())
@ -227,18 +227,18 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
int reparse = 0;
if (deleted)
reparse = 2;
else if (!(g_config->index.onChange && wfiles->GetFile(path_to_index))) {
std::optional<int64_t> write_time = LastWriteTime(path_to_index);
else if (!(g_config->index.onChange && wfiles->getFile(path_to_index))) {
std::optional<int64_t> write_time = lastWriteTime(path_to_index);
if (!write_time) {
deleted = true;
} else {
if (vfs->Stamp(path_to_index, *write_time, no_linkage ? 2 : 0))
if (vfs->stamp(path_to_index, *write_time, no_linkage ? 2 : 0))
reparse = 1;
if (request.path != path_to_index) {
std::optional<int64_t> mtime1 = LastWriteTime(request.path);
std::optional<int64_t> mtime1 = lastWriteTime(request.path);
if (!mtime1)
deleted = true;
else if (vfs->Stamp(request.path, *mtime1, no_linkage ? 2 : 0))
else if (vfs->stamp(request.path, *mtime1, no_linkage ? 2 : 0))
reparse = 2;
}
}
@ -258,15 +258,15 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (reparse < 2)
do {
std::unique_lock lock(GetFileMutex(path_to_index));
prev = RawCacheLoad(path_to_index);
std::unique_lock lock(getFileMutex(path_to_index));
prev = rawCacheLoad(path_to_index);
if (!prev || prev->no_linkage < no_linkage ||
CacheInvalid(vfs, prev.get(), path_to_index, entry.args,
cacheInvalid(vfs, prev.get(), path_to_index, entry.args,
std::nullopt))
break;
if (track)
for (const auto &dep : prev->dependencies) {
if (auto mtime1 = LastWriteTime(dep.first.val().str())) {
if (auto mtime1 = lastWriteTime(dep.first.val().str())) {
if (dep.second < *mtime1) {
reparse = 2;
LOG_V(1) << "timestamp changed for " << path_to_index << " via "
@ -285,12 +285,12 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (reparse == 2)
break;
if (vfs->Loaded(path_to_index))
if (vfs->loaded(path_to_index))
return true;
LOG_S(INFO) << "load cache for " << path_to_index;
auto dependencies = prev->dependencies;
IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
on_indexed->PushBack(std::move(update),
IndexUpdate update = IndexUpdate::createDelta(nullptr, prev.get());
on_indexed->pushBack(std::move(update),
request.mode != IndexMode::Background);
{
std::lock_guard lock1(vfs->mutex);
@ -303,10 +303,10 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
for (const auto &dep : dependencies) {
std::string path = dep.first.val().str();
if (!vfs->Stamp(path, dep.second, 1))
if (!vfs->stamp(path, dep.second, 1))
continue;
std::lock_guard lock1(GetFileMutex(path));
prev = RawCacheLoad(path);
std::lock_guard lock1(getFileMutex(path));
prev = rawCacheLoad(path);
if (!prev)
continue;
{
@ -319,8 +319,8 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
if (prev->no_linkage)
st.step = 3;
}
IndexUpdate update = IndexUpdate::CreateDelta(nullptr, prev.get());
on_indexed->PushBack(std::move(update),
IndexUpdate update = IndexUpdate::createDelta(nullptr, prev.get());
on_indexed->pushBack(std::move(update),
request.mode != IndexMode::Background);
if (entry.id >= 0) {
std::lock_guard lock2(project->mtx);
@ -348,20 +348,20 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
} else {
std::vector<std::pair<std::string, std::string>> remapped;
if (g_config->index.onChange) {
std::string content = wfiles->GetContent(path_to_index);
std::string content = wfiles->getContent(path_to_index);
if (content.size())
remapped.emplace_back(path_to_index, content);
}
bool ok;
indexes = idx::Index(completion, wfiles, vfs, entry.directory,
indexes = idx::index(completion, wfiles, vfs, entry.directory,
path_to_index, entry.args, remapped, no_linkage, ok);
if (!ok) {
if (request.id.Valid()) {
if (request.id.valid()) {
ResponseError err;
err.code = ErrorCode::InternalError;
err.message = "failed to index " + path_to_index;
pipeline::ReplyError(request.id, err);
pipeline::replyError(request.id, err);
}
return true;
}
@ -369,7 +369,7 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
for (std::unique_ptr<IndexFile> &curr : indexes) {
std::string path = curr->path;
if (!matcher.Matches(path)) {
if (!matcher.matches(path)) {
LOG_IF_S(INFO, loud) << "skip index for " << path;
continue;
}
@ -378,10 +378,10 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
LOG_IF_S(INFO, loud) << "store index for " << path
<< " (delta: " << !!prev << ")";
{
std::lock_guard lock(GetFileMutex(path));
int loaded = vfs->Loaded(path), retain = g_config->cache.retainInMemory;
std::lock_guard lock(getFileMutex(path));
int loaded = vfs->loaded(path), retain = g_config->cache.retainInMemory;
if (loaded)
prev = RawCacheLoad(path);
prev = rawCacheLoad(path);
else
prev.reset();
if (retain > 0 && retain <= loaded + 1) {
@ -391,21 +391,21 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
std::string().swap(it.first->second.index.file_contents);
}
if (g_config->cache.directory.size()) {
std::string cache_path = GetCachePath(path);
std::string cache_path = getCachePath(path);
if (deleted) {
(void)sys::fs::remove(cache_path);
(void)sys::fs::remove(AppendSerializationFormat(cache_path));
(void)sys::fs::remove(appendSerializationFormat(cache_path));
} else {
if (g_config->cache.hierarchicalPath)
sys::fs::create_directories(
sys::path::parent_path(cache_path, sys::path::Style::posix),
true);
WriteToFile(cache_path, curr->file_contents);
WriteToFile(AppendSerializationFormat(cache_path),
Serialize(g_config->cache.format, *curr));
writeToFile(cache_path, curr->file_contents);
writeToFile(appendSerializationFormat(cache_path),
serialize(g_config->cache.format, *curr));
}
}
on_indexed->PushBack(IndexUpdate::CreateDelta(prev.get(), curr.get()),
on_indexed->pushBack(IndexUpdate::createDelta(prev.get(), curr.get()),
request.mode != IndexMode::Background);
{
std::lock_guard lock1(vfs->mutex);
@ -423,9 +423,9 @@ bool Indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
return true;
}
void Quit(SemaManager &manager) {
quit.store(true, std::memory_order_relaxed);
manager.Quit();
void quit(SemaManager &manager) {
g_quit.store(true, std::memory_order_relaxed);
manager.quit();
{ std::lock_guard lock(index_request->mutex_); }
indexer_waiter->cv.notify_all();
@ -437,18 +437,18 @@ void Quit(SemaManager &manager) {
} // namespace
void ThreadEnter() {
void threadEnter() {
std::lock_guard lock(thread_mtx);
active_threads++;
}
void ThreadLeave() {
void threadLeave() {
std::lock_guard lock(thread_mtx);
if (!--active_threads)
no_active_threads.notify_one();
}
void Init() {
void init() {
main_waiter = new MultiQueueWaiter;
on_request = new ThreadedQueue<InMessage>(main_waiter);
on_indexed = new ThreadedQueue<IndexUpdate>(main_waiter);
@ -460,49 +460,49 @@ void Init() {
for_stdout = new ThreadedQueue<std::string>(stdout_waiter);
}
void Indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
void indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
WorkingFiles *wfiles) {
GroupMatch matcher(g_config->index.whitelist, g_config->index.blacklist);
while (true)
if (!Indexer_Parse(manager, wfiles, project, vfs, matcher))
if (indexer_waiter->Wait(quit, index_request))
if (!indexer_Parse(manager, wfiles, project, vfs, matcher))
if (indexer_waiter->wait(g_quit, index_request))
break;
}
void Main_OnIndexed(DB *db, WorkingFiles *wfiles, IndexUpdate *update) {
void main_OnIndexed(DB *db, WorkingFiles *wfiles, IndexUpdate *update) {
if (update->refresh) {
LOG_S(INFO)
<< "loaded project. Refresh semantic highlight for all working file.";
std::lock_guard lock(wfiles->mutex);
for (auto &[f, wf] : wfiles->files) {
std::string path = LowerPathIfInsensitive(f);
std::string path = lowerPathIfInsensitive(f);
if (db->name2file_id.find(path) == db->name2file_id.end())
continue;
QueryFile &file = db->files[db->name2file_id[path]];
EmitSemanticHighlight(db, wf.get(), file);
emitSemanticHighlight(db, wf.get(), file);
}
return;
}
db->ApplyIndexUpdate(update);
db->applyIndexUpdate(update);
// Update indexed content, skipped ranges, and semantic highlighting.
if (update->files_def_update) {
auto &def_u = *update->files_def_update;
if (WorkingFile *wfile = wfiles->GetFile(def_u.first.path)) {
if (WorkingFile *wfile = wfiles->getFile(def_u.first.path)) {
// FIXME With index.onChange: true, use buffer_content only for
// request.path
wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content
wfile->setIndexContent(g_config->index.onChange ? wfile->buffer_content
: def_u.second);
QueryFile &file = db->files[update->file_id];
EmitSkippedRanges(wfile, file);
EmitSemanticHighlight(db, wfile, file);
emitSkippedRanges(wfile, file);
emitSemanticHighlight(db, wfile, file);
}
}
}
void LaunchStdin() {
ThreadEnter();
void launchStdin() {
threadEnter();
std::thread([]() {
set_thread_name("stdin");
std::string str;
@ -546,9 +546,9 @@ void LaunchStdin() {
break;
RequestId id;
std::string method;
ReflectMember(reader, "id", id);
ReflectMember(reader, "method", method);
if (id.Valid())
reflectMember(reader, "id", id);
reflectMember(reader, "method", method);
if (id.valid())
LOG_V(2) << "receive RequestMessage: " << id.value << " " << method;
else
LOG_V(2) << "receive NotificationMessage " << method;
@ -556,7 +556,7 @@ void LaunchStdin() {
continue;
received_exit = method == "exit";
// g_config is not available before "initialize". Use 0 in that case.
on_request->PushBack(
on_request->pushBack(
{id, std::move(method), std::move(message), std::move(document),
chrono::steady_clock::now() +
chrono::milliseconds(g_config ? g_config->request.timeout : 0)});
@ -572,33 +572,33 @@ void LaunchStdin() {
std::copy(str.begin(), str.end(), message.get());
auto document = std::make_unique<rapidjson::Document>();
document->Parse(message.get(), str.size());
on_request->PushBack({RequestId(), std::string("exit"),
on_request->pushBack({RequestId(), std::string("exit"),
std::move(message), std::move(document),
chrono::steady_clock::now()});
}
ThreadLeave();
threadLeave();
}).detach();
}
void LaunchStdout() {
ThreadEnter();
void launchStdout() {
threadEnter();
std::thread([]() {
set_thread_name("stdout");
while (true) {
std::vector<std::string> messages = for_stdout->DequeueAll();
std::vector<std::string> messages = for_stdout->dequeueAll();
for (auto &s : messages) {
llvm::outs() << "Content-Length: " << s.size() << "\r\n\r\n" << s;
llvm::outs().flush();
}
if (stdout_waiter->Wait(quit, for_stdout))
if (stdout_waiter->wait(g_quit, for_stdout))
break;
}
ThreadLeave();
threadLeave();
}).detach();
}
void MainLoop() {
void mainLoop() {
Project project;
WorkingFiles wfiles;
VFS vfs;
@ -607,16 +607,16 @@ void MainLoop() {
&project, &wfiles,
[&](std::string path, std::vector<Diagnostic> diagnostics) {
PublishDiagnosticParam params;
params.uri = DocumentUri::FromPath(path);
params.uri = DocumentUri::fromPath(path);
params.diagnostics = diagnostics;
Notify("textDocument/publishDiagnostics", params);
notify("textDocument/publishDiagnostics", params);
},
[](RequestId id) {
if (id.Valid()) {
if (id.valid()) {
ResponseError err;
err.code = ErrorCode::InternalError;
err.message = "drop older completion request";
ReplyError(id, err);
replyError(id, err);
}
});
@ -643,7 +643,7 @@ void MainLoop() {
if (backlog[0].backlog_path.size()) {
if (now < backlog[0].deadline)
break;
handler.Run(backlog[0]);
handler.run(backlog[0]);
path2backlog[backlog[0].backlog_path].pop_front();
}
backlog.pop_front();
@ -651,11 +651,11 @@ void MainLoop() {
handler.overdue = false;
}
std::vector<InMessage> messages = on_request->DequeueAll();
std::vector<InMessage> messages = on_request->dequeueAll();
bool did_work = messages.size();
for (InMessage &message : messages)
try {
handler.Run(message);
handler.run(message);
} catch (NotIndexed &ex) {
backlog.push_back(std::move(message));
backlog.back().backlog_path = ex.path;
@ -664,17 +664,17 @@ void MainLoop() {
bool indexed = false;
for (int i = 20; i--;) {
std::optional<IndexUpdate> update = on_indexed->TryPopFront();
std::optional<IndexUpdate> update = on_indexed->tryPopFront();
if (!update)
break;
did_work = true;
indexed = true;
Main_OnIndexed(&db, &wfiles, &*update);
main_OnIndexed(&db, &wfiles, &*update);
if (update->files_def_update) {
auto it = path2backlog.find(update->files_def_update->first.path);
if (it != path2backlog.end()) {
for (auto &message : it->second) {
handler.Run(*message);
handler.run(*message);
message->backlog_path.clear();
}
path2backlog.erase(it);
@ -684,24 +684,24 @@ void MainLoop() {
if (did_work) {
has_indexed |= indexed;
if (quit.load(std::memory_order_relaxed))
if (g_quit.load(std::memory_order_relaxed))
break;
} else {
if (has_indexed) {
FreeUnusedMemory();
freeUnusedMemory();
has_indexed = false;
}
if (backlog.empty())
main_waiter->Wait(quit, on_indexed, on_request);
main_waiter->wait(g_quit, on_indexed, on_request);
else
main_waiter->WaitUntil(backlog[0].deadline, on_indexed, on_request);
main_waiter->waitUntil(backlog[0].deadline, on_indexed, on_request);
}
}
Quit(manager);
quit(manager);
}
void Standalone(const std::string &root) {
void standalone(const std::string &root) {
Project project;
WorkingFiles wfiles;
VFS vfs;
@ -717,7 +717,7 @@ void Standalone(const std::string &root) {
handler.manager = &manager;
handler.include_complete = &complete;
StandaloneInitialize(handler, root);
standaloneInitialize(handler, root);
bool tty = sys::Process::StandardOutIsDisplayed();
if (tty) {
@ -727,7 +727,7 @@ void Standalone(const std::string &root) {
printf("entries: %5d\n", entries);
}
while (1) {
(void)on_indexed->DequeueAll();
(void)on_indexed->dequeueAll();
int pending = pending_index_requests;
if (tty) {
printf("\rpending: %5d", pending);
@ -739,24 +739,24 @@ void Standalone(const std::string &root) {
}
if (tty)
puts("");
Quit(manager);
quit(manager);
}
void Index(const std::string &path, const std::vector<const char *> &args,
void index(const std::string &path, const std::vector<const char *> &args,
IndexMode mode, bool must_exist, RequestId id) {
pending_index_requests++;
index_request->PushBack({path, args, mode, must_exist, id},
index_request->pushBack({path, args, mode, must_exist, id},
mode != IndexMode::Background);
}
void RemoveCache(const std::string &path) {
void removeCache(const std::string &path) {
if (g_config->cache.directory.size()) {
std::lock_guard lock(g_index_mutex);
g_index.erase(path);
}
}
std::optional<std::string> LoadIndexedContent(const std::string &path) {
std::optional<std::string> loadIndexedContent(const std::string &path) {
if (g_config->cache.directory.empty()) {
std::shared_lock lock(g_index_mutex);
auto it = g_index.find(path);
@ -764,10 +764,10 @@ std::optional<std::string> LoadIndexedContent(const std::string &path) {
return {};
return it->second.content;
}
return ReadContent(GetCachePath(path));
return readContent(getCachePath(path));
}
void NotifyOrRequest(const char *method, bool request,
void notifyOrRequest(const char *method, bool request,
const std::function<void(JsonWriter &)> &fn) {
rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> w(output);
@ -784,11 +784,12 @@ void NotifyOrRequest(const char *method, bool request,
JsonWriter writer(&w);
fn(writer);
w.EndObject();
LOG_V(2) << (request ? "RequestMessage: " : "NotificationMessage: ") << method;
for_stdout->PushBack(output.GetString());
LOG_V(2) << (request ? "RequestMessage: " : "NotificationMessage: ")
<< method;
for_stdout->pushBack(output.GetString());
}
static void Reply(RequestId id, const char *key,
static void reply(RequestId id, const char *key,
const std::function<void(JsonWriter &)> &fn) {
rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> w(output);
@ -811,17 +812,17 @@ static void Reply(RequestId id, const char *key,
JsonWriter writer(&w);
fn(writer);
w.EndObject();
if (id.Valid())
if (id.valid())
LOG_V(2) << "respond to RequestMessage: " << id.value;
for_stdout->PushBack(output.GetString());
for_stdout->pushBack(output.GetString());
}
void Reply(RequestId id, const std::function<void(JsonWriter &)> &fn) {
Reply(id, "result", fn);
void reply(RequestId id, const std::function<void(JsonWriter &)> &fn) {
reply(id, "result", fn);
}
void ReplyError(RequestId id, const std::function<void(JsonWriter &)> &fn) {
Reply(id, "error", fn);
void replyError(RequestId id, const std::function<void(JsonWriter &)> &fn) {
reply(id, "error", fn);
}
} // namespace pipeline
} // namespace ccls

View File

@ -27,9 +27,9 @@ struct VFS {
std::unordered_map<std::string, State> state;
std::mutex mutex;
void Clear();
int Loaded(const std::string &path);
bool Stamp(const std::string &path, int64_t ts, int step);
void clear();
int loaded(const std::string &path);
bool stamp(const std::string &path, int64_t ts, int step);
};
enum class IndexMode {
@ -40,39 +40,39 @@ enum class IndexMode {
};
namespace pipeline {
extern std::atomic<bool> quit;
extern std::atomic<bool> g_quit;
extern std::atomic<int64_t> loaded_ts, pending_index_requests;
extern int64_t tick;
void ThreadEnter();
void ThreadLeave();
void Init();
void LaunchStdin();
void LaunchStdout();
void Indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
void threadEnter();
void threadLeave();
void init();
void launchStdin();
void launchStdout();
void indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
WorkingFiles *wfiles);
void MainLoop();
void Standalone(const std::string &root);
void mainLoop();
void standalone(const std::string &root);
void Index(const std::string &path, const std::vector<const char *> &args,
void index(const std::string &path, const std::vector<const char *> &args,
IndexMode mode, bool must_exist, RequestId id = {});
void RemoveCache(const std::string &path);
std::optional<std::string> LoadIndexedContent(const std::string& path);
void removeCache(const std::string &path);
std::optional<std::string> loadIndexedContent(const std::string &path);
void NotifyOrRequest(const char *method, bool request,
void notifyOrRequest(const char *method, bool request,
const std::function<void(JsonWriter &)> &fn);
template <typename T> void Notify(const char *method, T &result) {
NotifyOrRequest(method, false, [&](JsonWriter &w) { Reflect(w, result); });
template <typename T> void notify(const char *method, T &result) {
notifyOrRequest(method, false, [&](JsonWriter &w) { reflect(w, result); });
}
template <typename T> void Request(const char *method, T &result) {
NotifyOrRequest(method, true, [&](JsonWriter &w) { Reflect(w, result); });
template <typename T> void request(const char *method, T &result) {
notifyOrRequest(method, true, [&](JsonWriter &w) { reflect(w, result); });
}
void Reply(RequestId id, const std::function<void(JsonWriter &)> &fn);
void reply(RequestId id, const std::function<void(JsonWriter &)> &fn);
void ReplyError(RequestId id, const std::function<void(JsonWriter &)> &fn);
template <typename T> void ReplyError(RequestId id, T &result) {
ReplyError(id, [&](JsonWriter &w) { Reflect(w, result); });
void replyError(RequestId id, const std::function<void(JsonWriter &)> &fn);
template <typename T> void replyError(RequestId id, T &result) {
replyError(id, [&](JsonWriter &w) { reflect(w, result); });
}
} // namespace pipeline
} // namespace ccls

View File

@ -8,13 +8,13 @@
#include <vector>
namespace ccls {
std::string NormalizePath(const std::string &path);
std::string normalizePath(const std::string &path);
// Free any unused memory and return it to the system.
void FreeUnusedMemory();
void freeUnusedMemory();
// Stop self and wait for SIGCONT.
void TraceMe();
void traceMe();
void SpawnThread(void *(*fn)(void *), void *arg);
void spawnThread(void *(*fn)(void *), void *arg);
} // namespace ccls

View File

@ -37,22 +37,22 @@
namespace ccls {
namespace pipeline {
void ThreadEnter();
void threadEnter();
}
std::string NormalizePath(const std::string &path) {
llvm::SmallString<256> P(path);
llvm::sys::path::remove_dots(P, true);
return {P.data(), P.size()};
std::string normalizePath(const std::string &path) {
llvm::SmallString<256> p(path);
llvm::sys::path::remove_dots(p, true);
return {p.data(), p.size()};
}
void FreeUnusedMemory() {
void freeUnusedMemory() {
#ifdef __GLIBC__
malloc_trim(4 * 1024 * 1024);
#endif
}
void TraceMe() {
void traceMe() {
// If the environment variable is defined, wait for a debugger.
// In gdb, you need to invoke `signal SIGCONT` if you want ccls to continue
// after detaching.
@ -61,7 +61,7 @@ void TraceMe() {
raise(traceme[0] == 's' ? SIGSTOP : SIGTSTP);
}
void SpawnThread(void *(*fn)(void *), void *arg) {
void spawnThread(void *(*fn)(void *), void *arg) {
pthread_t thd;
pthread_attr_t attr;
struct rlimit rlim;
@ -71,7 +71,7 @@ void SpawnThread(void *(*fn)(void *), void *arg) {
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, stack_size);
pipeline::ThreadEnter();
pipeline::threadEnter();
pthread_create(&thd, &attr, fn, arg);
pthread_attr_destroy(&attr);
}

View File

@ -19,7 +19,7 @@
#include <thread>
namespace ccls {
std::string NormalizePath(const std::string &path) {
std::string normalizePath(const std::string &path) {
DWORD retval = 0;
TCHAR buffer[MAX_PATH] = TEXT("");
TCHAR **lpp_part = {NULL};
@ -40,14 +40,14 @@ std::string NormalizePath(const std::string &path) {
return result;
}
void FreeUnusedMemory() {}
void freeUnusedMemory() {}
// TODO Wait for debugger to attach
void TraceMe() {}
void traceMe() {}
void SpawnThread(void *(*fn)(void *), void *arg) {
void spawnThread(void *(*fn)(void *), void *arg) {
std::thread(fn, arg).detach();
}
}
} // namespace ccls
#endif

View File

@ -14,7 +14,7 @@
#include <stdlib.h>
namespace ccls {
Pos Pos::FromString(const std::string &encoded) {
Pos Pos::fromString(const std::string &encoded) {
char *p = const_cast<char *>(encoded.c_str());
uint16_t line = uint16_t(strtoul(p, &p, 10) - 1);
assert(*p == ':');
@ -23,13 +23,13 @@ Pos Pos::FromString(const std::string &encoded) {
return {line, column};
}
std::string Pos::ToString() {
std::string Pos::toString() {
char buf[99];
snprintf(buf, sizeof buf, "%d:%d", line + 1, column + 1);
return buf;
}
Range Range::FromString(const std::string &encoded) {
Range Range::fromString(const std::string &encoded) {
Pos start, end;
char *p = const_cast<char *>(encoded.c_str());
start.line = uint16_t(strtoul(p, &p, 10) - 1);
@ -46,53 +46,53 @@ Range Range::FromString(const std::string &encoded) {
return {start, end};
}
bool Range::Contains(int line, int column) const {
bool Range::contains(int line, int column) const {
if (line > INT16_MAX)
return false;
Pos p{(uint16_t)line, (int16_t)std::min<int>(column, INT16_MAX)};
return !(p < start) && p < end;
}
std::string Range::ToString() {
std::string Range::toString() {
char buf[99];
snprintf(buf, sizeof buf, "%d:%d-%d:%d", start.line + 1, start.column + 1,
end.line + 1, end.column + 1);
return buf;
}
void Reflect(JsonReader &vis, Pos &v) { v = Pos::FromString(vis.GetString()); }
void Reflect(JsonReader &vis, Range &v) {
v = Range::FromString(vis.GetString());
void reflect(JsonReader &vis, Pos &v) { v = Pos::fromString(vis.getString()); }
void reflect(JsonReader &vis, Range &v) {
v = Range::fromString(vis.getString());
}
void Reflect(JsonWriter &vis, Pos &v) {
std::string output = v.ToString();
vis.String(output.c_str(), output.size());
void reflect(JsonWriter &vis, Pos &v) {
std::string output = v.toString();
vis.string(output.c_str(), output.size());
}
void Reflect(JsonWriter &vis, Range &v) {
std::string output = v.ToString();
vis.String(output.c_str(), output.size());
void reflect(JsonWriter &vis, Range &v) {
std::string output = v.toString();
vis.string(output.c_str(), output.size());
}
void Reflect(BinaryReader &visitor, Pos &value) {
Reflect(visitor, value.line);
Reflect(visitor, value.column);
void reflect(BinaryReader &visitor, Pos &value) {
reflect(visitor, value.line);
reflect(visitor, value.column);
}
void Reflect(BinaryReader &visitor, Range &value) {
Reflect(visitor, value.start.line);
Reflect(visitor, value.start.column);
Reflect(visitor, value.end.line);
Reflect(visitor, value.end.column);
void reflect(BinaryReader &visitor, Range &value) {
reflect(visitor, value.start.line);
reflect(visitor, value.start.column);
reflect(visitor, value.end.line);
reflect(visitor, value.end.column);
}
void Reflect(BinaryWriter &vis, Pos &v) {
Reflect(vis, v.line);
Reflect(vis, v.column);
void reflect(BinaryWriter &vis, Pos &v) {
reflect(vis, v.line);
reflect(vis, v.column);
}
void Reflect(BinaryWriter &vis, Range &v) {
Reflect(vis, v.start.line);
Reflect(vis, v.start.column);
Reflect(vis, v.end.line);
Reflect(vis, v.end.column);
void reflect(BinaryWriter &vis, Range &v) {
reflect(vis, v.start.line);
reflect(vis, v.start.column);
reflect(vis, v.end.line);
reflect(vis, v.end.column);
}
} // namespace ccls

View File

@ -13,10 +13,10 @@ struct Pos {
uint16_t line = 0;
int16_t column = -1;
static Pos FromString(const std::string &encoded);
static Pos fromString(const std::string &encoded);
bool Valid() const { return column >= 0; }
std::string ToString();
bool valid() const { return column >= 0; }
std::string toString();
// Compare two Positions and check if they are equal. Ignores the value of
// |interesting|.
@ -35,12 +35,12 @@ struct Range {
Pos start;
Pos end;
static Range FromString(const std::string &encoded);
static Range fromString(const std::string &encoded);
bool Valid() const { return start.Valid(); }
bool Contains(int line, int column) const;
bool valid() const { return start.valid(); }
bool contains(int line, int column) const;
std::string ToString();
std::string toString();
bool operator==(const Range &o) const {
return start == o.start && end == o.end;
@ -50,20 +50,20 @@ struct Range {
}
};
// Reflection
// reflection
struct JsonReader;
struct JsonWriter;
struct BinaryReader;
struct BinaryWriter;
void Reflect(JsonReader &visitor, Pos &value);
void Reflect(JsonReader &visitor, Range &value);
void Reflect(JsonWriter &visitor, Pos &value);
void Reflect(JsonWriter &visitor, Range &value);
void Reflect(BinaryReader &visitor, Pos &value);
void Reflect(BinaryReader &visitor, Range &value);
void Reflect(BinaryWriter &visitor, Pos &value);
void Reflect(BinaryWriter &visitor, Range &value);
void reflect(JsonReader &visitor, Pos &value);
void reflect(JsonReader &visitor, Range &value);
void reflect(JsonWriter &visitor, Pos &value);
void reflect(JsonWriter &visitor, Range &value);
void reflect(BinaryReader &visitor, Pos &value);
void reflect(BinaryReader &visitor, Range &value);
void reflect(BinaryWriter &visitor, Pos &value);
void reflect(BinaryWriter &visitor, Range &value);
} // namespace ccls
namespace std {

View File

@ -41,18 +41,18 @@ using namespace llvm;
namespace ccls {
std::pair<LanguageId, bool> lookupExtension(std::string_view filename) {
using namespace clang::driver;
auto I = types::lookupTypeForExtension(
auto i = types::lookupTypeForExtension(
sys::path::extension({filename.data(), filename.size()}).substr(1));
bool header = I == types::TY_CHeader || I == types::TY_CXXHeader ||
I == types::TY_ObjCXXHeader;
bool objc = types::isObjC(I);
bool header = i == types::TY_CHeader || i == types::TY_CXXHeader ||
i == types::TY_ObjCXXHeader;
bool objc = types::isObjC(i);
LanguageId ret;
if (types::isCXX(I))
ret = types::isCuda(I) ? LanguageId::Cuda
if (types::isCXX(i))
ret = types::isCuda(i) ? LanguageId::Cuda
: objc ? LanguageId::ObjCpp : LanguageId::Cpp;
else if (objc)
ret = LanguageId::ObjC;
else if (I == types::TY_C || I == types::TY_CHeader)
else if (i == types::TY_C || i == types::TY_CHeader)
ret = LanguageId::C;
else
ret = LanguageId::Unknown;
@ -84,55 +84,56 @@ struct ProjectProcessor {
LOG_S(WARNING) << toString(glob_or_err.takeError());
}
bool ExcludesArg(StringRef arg, int &i) {
bool excludesArg(StringRef arg, int &i) {
if (arg.startswith("-M")) {
if (arg == "-MF" || arg == "-MT" || arg == "-MQ")
i++;
return true;
}
return exclude_args.count(arg) || any_of(exclude_globs,
return exclude_args.count(arg) ||
any_of(exclude_globs,
[&](const GlobPattern &glob) { return glob.match(arg); });
}
// Expand %c %cpp ... in .ccls
void Process(Project::Entry &entry) {
void process(Project::Entry &entry) {
std::vector<const char *> args(entry.args.begin(),
entry.args.begin() + entry.compdb_size);
auto [lang, header] = lookupExtension(entry.filename);
for (int i = entry.compdb_size; i < entry.args.size(); i++) {
const char *arg = entry.args[i];
StringRef A(arg);
if (A[0] == '%') {
StringRef a(arg);
if (a[0] == '%') {
bool ok = false;
for (;;) {
if (A.consume_front("%c "))
if (a.consume_front("%c "))
ok |= lang == LanguageId::C;
else if (A.consume_front("%h "))
else if (a.consume_front("%h "))
ok |= lang == LanguageId::C && header;
else if (A.consume_front("%cpp "))
else if (a.consume_front("%cpp "))
ok |= lang == LanguageId::Cpp;
else if (A.consume_front("%cu "))
else if (a.consume_front("%cu "))
ok |= lang == LanguageId::Cuda;
else if (A.consume_front("%hpp "))
else if (a.consume_front("%hpp "))
ok |= lang == LanguageId::Cpp && header;
else if (A.consume_front("%objective-c "))
else if (a.consume_front("%objective-c "))
ok |= lang == LanguageId::ObjC;
else if (A.consume_front("%objective-cpp "))
else if (a.consume_front("%objective-cpp "))
ok |= lang == LanguageId::ObjCpp;
else
break;
}
if (ok)
args.push_back(A.data());
} else if (!ExcludesArg(A, i)) {
args.push_back(a.data());
} else if (!excludesArg(a, i)) {
args.push_back(arg);
}
}
entry.args = args;
GetSearchDirs(entry);
getSearchDirs(entry);
}
void GetSearchDirs(Project::Entry &entry) {
void getSearchDirs(Project::Entry &entry) {
#if LLVM_VERSION_MAJOR < 8
const std::string base_name = sys::path::filename(entry.filename);
size_t hash = std::hash<std::string>{}(entry.directory);
@ -160,9 +161,9 @@ struct ProjectProcessor {
auto args = entry.args;
args.push_back("-fsyntax-only");
for (const std::string &arg : g_config->clang.extraArgs)
args.push_back(Intern(arg));
args.push_back(Intern("-working-directory=" + entry.directory));
args.push_back(Intern("-resource-dir=" + g_config->clang.resourceDir));
args.push_back(intern(arg));
args.push_back(intern("-working-directory=" + entry.directory));
args.push_back(intern("-resource-dir=" + g_config->clang.resourceDir));
// a weird C++ deduction guide heap-use-after-free causes libclang to crash.
IgnoringDiagConsumer DiagC;
@ -196,8 +197,8 @@ struct ProjectProcessor {
HeaderSearchOptions &HeaderOpts = CI->getHeaderSearchOpts();
for (auto &E : HeaderOpts.UserEntries) {
std::string path =
NormalizePath(ResolveIfRelative(entry.directory, E.Path));
EnsureEndsInSlash(path);
normalizePath(resolveIfRelative(entry.directory, E.Path));
ensureEndsInSlash(path);
switch (E.Group) {
default:
folder.search_dir2kind[path] |= 2;
@ -215,42 +216,42 @@ struct ProjectProcessor {
};
std::vector<const char *>
ReadCompilerArgumentsFromFile(const std::string &path) {
auto MBOrErr = MemoryBuffer::getFile(path);
if (!MBOrErr)
readCompilerArgumentsFromFile(const std::string &path) {
auto mbOrErr = MemoryBuffer::getFile(path);
if (!mbOrErr)
return {};
std::vector<const char *> args;
for (line_iterator I(*MBOrErr.get(), true, '#'), E; I != E; ++I) {
std::string line = *I;
DoPathMapping(line);
args.push_back(Intern(line));
for (line_iterator i(*mbOrErr.get(), true, '#'), e; i != e; ++i) {
std::string line = *i;
doPathMapping(line);
args.push_back(intern(line));
}
return args;
}
bool AppendToCDB(const std::vector<const char *> &args) {
bool appendToCDB(const std::vector<const char *> &args) {
return args.size() && StringRef("%compile_commands.json") == args[0];
}
std::vector<const char *> GetFallback(const std::string path) {
std::vector<const char *> getFallback(const std::string path) {
std::vector<const char *> argv{"clang"};
if (sys::path::extension(path) == ".h")
argv.push_back("-xobjective-c++-header");
argv.push_back(Intern(path));
argv.push_back(intern(path));
return argv;
}
void LoadDirectoryListing(ProjectProcessor &proc, const std::string &root,
const StringSet<> &Seen) {
void loadDirectoryListing(ProjectProcessor &proc, const std::string &root,
const StringSet<> &seen) {
Project::Folder &folder = proc.folder;
std::vector<std::string> files;
auto GetDotCcls = [&root, &folder](std::string cur) {
auto getDotCcls = [&root, &folder](std::string cur) {
while (!(cur = sys::path::parent_path(cur)).empty()) {
auto it = folder.dot_ccls.find(cur);
if (it != folder.dot_ccls.end())
return it->second;
std::string normalized = NormalizePath(cur);
std::string normalized = normalizePath(cur);
// Break if outside of the project root.
if (normalized.size() <= root.size() ||
normalized.compare(0, root.size(), root) != 0)
@ -259,16 +260,17 @@ void LoadDirectoryListing(ProjectProcessor &proc, const std::string &root,
return folder.dot_ccls[root];
};
GetFilesInFolder(root, true /*recursive*/, true /*add_folder_to_path*/,
[&folder, &files, &Seen](const std::string &path) {
getFilesInFolder(root, true /*recursive*/, true /*add_folder_to_path*/,
[&folder, &files, &seen](const std::string &path) {
std::pair<LanguageId, bool> lang = lookupExtension(path);
if (lang.first != LanguageId::Unknown && !lang.second) {
if (!Seen.count(path))
if (!seen.count(path))
files.push_back(path);
} else if (sys::path::filename(path) == ".ccls") {
std::vector<const char *> args = ReadCompilerArgumentsFromFile(path);
folder.dot_ccls.emplace(sys::path::parent_path(path).str() + '/',
args);
std::vector<const char *> args =
readCompilerArgumentsFromFile(path);
folder.dot_ccls.emplace(
sys::path::parent_path(path).str() + '/', args);
std::string l;
for (size_t i = 0; i < args.size(); i++) {
if (i)
@ -281,31 +283,31 @@ void LoadDirectoryListing(ProjectProcessor &proc, const std::string &root,
// If the first line of .ccls is %compile_commands.json, append extra flags.
for (auto &e : folder.entries)
if (const auto &args = GetDotCcls(e.filename); AppendToCDB(args)) {
if (const auto &args = getDotCcls(e.filename); appendToCDB(args)) {
if (args.size())
e.args.insert(e.args.end(), args.begin() + 1, args.end());
proc.Process(e);
proc.process(e);
}
// Set flags for files not in compile_commands.json
for (const std::string &file : files)
if (const auto &args = GetDotCcls(file); !AppendToCDB(args)) {
if (const auto &args = getDotCcls(file); !appendToCDB(args)) {
Project::Entry e;
e.root = e.directory = root;
e.filename = file;
if (args.empty()) {
e.args = GetFallback(e.filename);
e.args = getFallback(e.filename);
} else {
e.args = args;
e.args.push_back(Intern(e.filename));
e.args.push_back(intern(e.filename));
}
proc.Process(e);
proc.process(e);
folder.entries.push_back(e);
}
}
// Computes a score based on how well |a| and |b| match. This is used for
// argument guessing.
int ComputeGuessScore(std::string_view a, std::string_view b) {
int computeGuessScore(std::string_view a, std::string_view b) {
int score = 0;
unsigned h = 0;
llvm::SmallDenseMap<unsigned, int> m;
@ -345,50 +347,50 @@ int ComputeGuessScore(std::string_view a, std::string_view b) {
} // namespace
void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
SmallString<256> CDBDir, Path, StdinPath;
void Project::loadDirectory(const std::string &root, Project::Folder &folder) {
SmallString<256> cdbDir, path, stdinPath;
std::string err_msg;
folder.entries.clear();
if (g_config->compilationDatabaseCommand.empty()) {
CDBDir = root;
cdbDir = root;
if (g_config->compilationDatabaseDirectory.size()) {
if (sys::path::is_absolute(g_config->compilationDatabaseDirectory))
CDBDir = g_config->compilationDatabaseDirectory;
cdbDir = g_config->compilationDatabaseDirectory;
else
sys::path::append(CDBDir, g_config->compilationDatabaseDirectory);
sys::path::append(cdbDir, g_config->compilationDatabaseDirectory);
}
sys::path::append(Path, CDBDir, "compile_commands.json");
sys::path::append(path, cdbDir, "compile_commands.json");
} else {
// If `compilationDatabaseCommand` is specified, execute it to get the
// compdb.
#ifdef _WIN32
char tmpdir[L_tmpnam];
tmpnam_s(tmpdir, L_tmpnam);
CDBDir = tmpdir;
cdbDir = tmpdir;
if (sys::fs::create_directory(tmpdir, false))
return;
#else
char tmpdir[] = "/tmp/ccls-compdb-XXXXXX";
if (!mkdtemp(tmpdir))
return;
CDBDir = tmpdir;
cdbDir = tmpdir;
#endif
sys::path::append(Path, CDBDir, "compile_commands.json");
sys::path::append(StdinPath, CDBDir, "stdin");
sys::path::append(path, cdbDir, "compile_commands.json");
sys::path::append(stdinPath, cdbDir, "stdin");
{
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
JsonWriter json_writer(&writer);
Reflect(json_writer, *g_config);
reflect(json_writer, *g_config);
std::string input = sb.GetString();
FILE *fout = fopen(StdinPath.c_str(), "wb");
FILE *fout = fopen(stdinPath.c_str(), "wb");
fwrite(input.c_str(), input.size(), 1, fout);
fclose(fout);
}
std::array<Optional<StringRef>, 3> Redir{StringRef(StdinPath),
StringRef(Path), StringRef()};
std::array<Optional<StringRef>, 3> redir{StringRef(stdinPath),
StringRef(path), StringRef()};
std::vector<StringRef> args{g_config->compilationDatabaseCommand, root};
if (sys::ExecuteAndWait(args[0], args, llvm::None, Redir, 0, 0, &err_msg) <
if (sys::ExecuteAndWait(args[0], args, llvm::None, redir, 0, 0, &err_msg) <
0) {
LOG_S(ERROR) << "failed to execute " << args[0].str() << " "
<< args[1].str() << ": " << err_msg;
@ -396,50 +398,50 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
}
}
std::unique_ptr<tooling::CompilationDatabase> CDB =
tooling::CompilationDatabase::loadFromDirectory(CDBDir, err_msg);
std::unique_ptr<tooling::CompilationDatabase> cdb =
tooling::CompilationDatabase::loadFromDirectory(cdbDir, err_msg);
if (!g_config->compilationDatabaseCommand.empty()) {
#ifdef _WIN32
DeleteFileA(StdinPath.c_str());
DeleteFileA(Path.c_str());
RemoveDirectoryA(CDBDir.c_str());
DeleteFileA(stdinPath.c_str());
DeleteFileA(path.c_str());
RemoveDirectoryA(cdbDir.c_str());
#else
unlink(StdinPath.c_str());
unlink(Path.c_str());
rmdir(CDBDir.c_str());
unlink(stdinPath.c_str());
unlink(path.c_str());
rmdir(cdbDir.c_str());
#endif
}
ProjectProcessor proc(folder);
StringSet<> Seen;
StringSet<> seen;
std::vector<Project::Entry> result;
if (!CDB) {
if (g_config->compilationDatabaseCommand.size() || sys::fs::exists(Path))
LOG_S(ERROR) << "failed to load " << Path.c_str();
if (!cdb) {
if (g_config->compilationDatabaseCommand.size() || sys::fs::exists(path))
LOG_S(ERROR) << "failed to load " << path.c_str();
} else {
LOG_S(INFO) << "loaded " << Path.c_str();
for (tooling::CompileCommand &Cmd : CDB->getAllCompileCommands()) {
LOG_S(INFO) << "loaded " << path.c_str();
for (tooling::CompileCommand &cmd : cdb->getAllCompileCommands()) {
static bool once;
Project::Entry entry;
entry.root = root;
DoPathMapping(entry.root);
doPathMapping(entry.root);
// If workspace folder is real/ but entries use symlink/, convert to
// real/.
entry.directory = RealPath(Cmd.Directory);
NormalizeFolder(entry.directory);
DoPathMapping(entry.directory);
entry.directory = realPath(cmd.Directory);
normalizeFolder(entry.directory);
doPathMapping(entry.directory);
entry.filename =
RealPath(ResolveIfRelative(entry.directory, Cmd.Filename));
NormalizeFolder(entry.filename);
DoPathMapping(entry.filename);
realPath(resolveIfRelative(entry.directory, cmd.Filename));
normalizeFolder(entry.filename);
doPathMapping(entry.filename);
std::vector<std::string> args = std::move(Cmd.CommandLine);
std::vector<std::string> args = std::move(cmd.CommandLine);
entry.args.reserve(args.size());
for (int i = 0; i < args.size(); i++) {
DoPathMapping(args[i]);
if (!proc.ExcludesArg(args[i], i))
entry.args.push_back(Intern(args[i]));
doPathMapping(args[i]);
if (!proc.excludesArg(args[i], i))
entry.args.push_back(intern(args[i]));
}
entry.compdb_size = entry.args.size();
@ -452,27 +454,27 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
llvm::vfs::getRealFileSystem()->setCurrentWorkingDirectory(
entry.directory);
}
proc.GetSearchDirs(entry);
proc.getSearchDirs(entry);
if (Seen.insert(entry.filename).second)
if (seen.insert(entry.filename).second)
folder.entries.push_back(entry);
}
}
// Use directory listing if .ccls exists or compile_commands.json does not
// exist.
Path.clear();
sys::path::append(Path, root, ".ccls");
if (sys::fs::exists(Path))
LoadDirectoryListing(proc, root, Seen);
path.clear();
sys::path::append(path, root, ".ccls");
if (sys::fs::exists(path))
loadDirectoryListing(proc, root, seen);
}
void Project::Load(const std::string &root) {
void Project::load(const std::string &root) {
assert(root.back() == '/');
std::lock_guard lock(mtx);
Folder &folder = root2folder[root];
LoadDirectory(root, folder);
loadDirectory(root, folder);
for (auto &[path, kind] : folder.search_dir2kind)
LOG_S(INFO) << "search directory: " << path << ' ' << " \"< "[kind];
@ -484,7 +486,7 @@ void Project::Load(const std::string &root) {
}
}
Project::Entry Project::FindEntry(const std::string &path, bool can_redirect,
Project::Entry Project::findEntry(const std::string &path, bool can_redirect,
bool must_exist) {
std::string best_dot_ccls_root;
Project::Folder *best_dot_ccls_folder = nullptr;
@ -525,17 +527,17 @@ Project::Entry Project::FindEntry(const std::string &path, bool can_redirect,
}
bool append = false;
if (best_dot_ccls_args && !(append = AppendToCDB(*best_dot_ccls_args)) &&
if (best_dot_ccls_args && !(append = appendToCDB(*best_dot_ccls_args)) &&
!exact_match) {
// If the first line is not %compile_commands.json, override the compdb
// match if it is not an exact match.
ret.root = ret.directory = best_dot_ccls_root;
ret.filename = path;
if (best_dot_ccls_args->empty()) {
ret.args = GetFallback(path);
ret.args = getFallback(path);
} else {
ret.args = *best_dot_ccls_args;
ret.args.push_back(Intern(path));
ret.args.push_back(intern(path));
}
} else {
// If the first line is %compile_commands.json, find the matching compdb
@ -549,7 +551,7 @@ Project::Entry Project::FindEntry(const std::string &path, bool can_redirect,
if (StringRef(path).startswith(root))
for (const Entry &e : folder.entries)
if (e.compdb_size) {
int score = ComputeGuessScore(path, e.filename);
int score = computeGuessScore(path, e.filename);
if (score > best_score) {
best_score = score;
best_compdb_folder = &folder;
@ -560,7 +562,7 @@ Project::Entry Project::FindEntry(const std::string &path, bool can_redirect,
}
if (!best) {
ret.root = ret.directory = g_config->fallbackFolder;
ret.args = GetFallback(path);
ret.args = getFallback(path);
} else {
// The entry may have different filename but it doesn't matter when
// building CompilerInvocation. The main filename is specified
@ -580,41 +582,41 @@ Project::Entry Project::FindEntry(const std::string &path, bool can_redirect,
ret.args.insert(ret.args.end(), best_dot_ccls_args->begin() + 1,
best_dot_ccls_args->end());
if (best_compdb_folder)
ProjectProcessor(*best_compdb_folder).Process(ret);
ProjectProcessor(*best_compdb_folder).process(ret);
else if (best_dot_ccls_folder)
ProjectProcessor(*best_dot_ccls_folder).Process(ret);
ProjectProcessor(*best_dot_ccls_folder).process(ret);
for (const std::string &arg : g_config->clang.extraArgs)
ret.args.push_back(Intern(arg));
ret.args.push_back(Intern("-working-directory=" + ret.directory));
ret.args.push_back(intern(arg));
ret.args.push_back(intern("-working-directory=" + ret.directory));
return ret;
}
void Project::Index(WorkingFiles *wfiles, RequestId id) {
void Project::index(WorkingFiles *wfiles, RequestId id) {
auto &gi = g_config->index;
GroupMatch match(gi.whitelist, gi.blacklist),
match_i(gi.initialWhitelist, gi.initialBlacklist);
std::vector<const char *> args, extra_args;
for (const std::string &arg : g_config->clang.extraArgs)
extra_args.push_back(Intern(arg));
extra_args.push_back(intern(arg));
{
std::lock_guard lock(mtx);
for (auto &[root, folder] : root2folder) {
int i = 0;
for (const Project::Entry &entry : folder.entries) {
std::string reason;
if (match.Matches(entry.filename, &reason) &&
match_i.Matches(entry.filename, &reason)) {
bool interactive = wfiles->GetFile(entry.filename) != nullptr;
if (match.matches(entry.filename, &reason) &&
match_i.matches(entry.filename, &reason)) {
bool interactive = wfiles->getFile(entry.filename) != nullptr;
args = entry.args;
args.insert(args.end(), extra_args.begin(), extra_args.end());
args.push_back(Intern("-working-directory=" + entry.directory));
pipeline::Index(entry.filename, args,
args.push_back(intern("-working-directory=" + entry.directory));
pipeline::index(entry.filename, args,
interactive ? IndexMode::Normal
: IndexMode::Background,
false, id);
} else {
LOG_V(1) << "[" << i << "/" << folder.entries.size() << "]: " << reason
<< "; skip " << entry.filename;
LOG_V(1) << "[" << i << "/" << folder.entries.size()
<< "]: " << reason << "; skip " << entry.filename;
}
i++;
}
@ -624,16 +626,16 @@ void Project::Index(WorkingFiles *wfiles, RequestId id) {
pipeline::loaded_ts = pipeline::tick;
// Dummy request to indicate that project is loaded and
// trigger refreshing semantic highlight for all working files.
pipeline::Index("", {}, IndexMode::Background, false);
pipeline::index("", {}, IndexMode::Background, false);
}
void Project::IndexRelated(const std::string &path) {
void Project::indexRelated(const std::string &path) {
auto &gi = g_config->index;
GroupMatch match(gi.whitelist, gi.blacklist);
std::string stem = sys::path::stem(path);
std::vector<const char *> args, extra_args;
for (const std::string &arg : g_config->clang.extraArgs)
extra_args.push_back(Intern(arg));
extra_args.push_back(intern(arg));
std::lock_guard lock(mtx);
for (auto &[root, folder] : root2folder)
if (StringRef(path).startswith(root)) {
@ -641,10 +643,10 @@ void Project::IndexRelated(const std::string &path) {
std::string reason;
args = entry.args;
args.insert(args.end(), extra_args.begin(), extra_args.end());
args.push_back(Intern("-working-directory=" + entry.directory));
args.push_back(intern("-working-directory=" + entry.directory));
if (sys::path::stem(entry.filename) == stem && entry.filename != path &&
match.Matches(entry.filename, &reason))
pipeline::Index(entry.filename, args, IndexMode::Background, true);
match.matches(entry.filename, &reason))
pipeline::index(entry.filename, args, IndexMode::Background, true);
}
break;
}

View File

@ -51,20 +51,20 @@ struct Project {
// will affect flags in their subtrees (relative paths are relative to the
// project root, not subdirectories). For compile_commands.json, its entries
// are indexed.
void Load(const std::string &root);
void LoadDirectory(const std::string &root, Folder &folder);
void load(const std::string &root);
void loadDirectory(const std::string &root, Folder &folder);
// Lookup the CompilationEntry for |filename|. If no entry was found this
// will infer one based on existing project structure.
Entry FindEntry(const std::string &path, bool can_redirect, bool must_exist);
Entry findEntry(const std::string &path, bool can_redirect, bool must_exist);
// If the client has overridden the flags, or specified them for a file
// that is not in the compilation_database.json make sure those changes
// are permanent.
void SetArgsForFile(const std::vector<const char *> &args,
void setArgsForFile(const std::vector<const char *> &args,
const std::string &path);
void Index(WorkingFiles *wfiles, RequestId id);
void IndexRelated(const std::string &path);
void index(WorkingFiles *wfiles, RequestId id);
void indexRelated(const std::string &path);
};
} // namespace ccls

View File

@ -10,17 +10,17 @@
#include <rapidjson/document.h>
#include <assert.h>
#include <stdint.h>
#include <limits.h>
#include <functional>
#include <limits.h>
#include <optional>
#include <stdint.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
namespace ccls {
namespace {
void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Use &use) {
void assignFileId(const Lid2file_id &lid2file_id, int file_id, Use &use) {
if (use.file_id == -1)
use.file_id = file_id;
else
@ -28,12 +28,12 @@ void AssignFileId(const Lid2file_id &lid2file_id, int file_id, Use &use) {
}
template <typename T>
void AddRange(std::vector<T> &into, const std::vector<T> &from) {
void addRange(std::vector<T> &into, const std::vector<T> &from) {
into.insert(into.end(), from.begin(), from.end());
}
template <typename T>
void RemoveRange(std::vector<T> &from, const std::vector<T> &to_remove) {
void removeRange(std::vector<T> &from, const std::vector<T> &to_remove) {
if (to_remove.size()) {
std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end());
from.erase(
@ -43,7 +43,7 @@ void RemoveRange(std::vector<T> &from, const std::vector<T> &to_remove) {
}
}
QueryFile::DefUpdate BuildFileDefUpdate(IndexFile &&indexed) {
QueryFile::DefUpdate buildFileDefUpdate(IndexFile &&indexed) {
QueryFile::Def def;
def.path = std::move(indexed.path);
def.args = std::move(indexed.args);
@ -58,7 +58,7 @@ QueryFile::DefUpdate BuildFileDefUpdate(IndexFile &&indexed) {
// Returns true if an element with the same file is found.
template <typename Q>
bool TryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
bool tryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
for (auto &def1 : def_list)
if (def1.file_id == def.file_id) {
def1 = std::move(def);
@ -69,21 +69,21 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
} // namespace
template <typename T> Vec<T> Convert(const std::vector<T> &o) {
template <typename T> Vec<T> convert(const std::vector<T> &o) {
Vec<T> r{std::make_unique<T[]>(o.size()), (int)o.size()};
std::copy(o.begin(), o.end(), r.begin());
return r;
}
QueryFunc::Def Convert(const IndexFunc::Def &o) {
QueryFunc::Def convert(const IndexFunc::Def &o) {
QueryFunc::Def r;
r.detailed_name = o.detailed_name;
r.hover = o.hover;
r.comments = o.comments;
r.spell = o.spell;
r.bases = Convert(o.bases);
r.vars = Convert(o.vars);
r.callees = Convert(o.callees);
r.bases = convert(o.bases);
r.vars = convert(o.vars);
r.callees = convert(o.callees);
// no file_id
r.qual_name_offset = o.qual_name_offset;
r.short_name_offset = o.short_name_offset;
@ -94,16 +94,16 @@ QueryFunc::Def Convert(const IndexFunc::Def &o) {
return r;
}
QueryType::Def Convert(const IndexType::Def &o) {
QueryType::Def convert(const IndexType::Def &o) {
QueryType::Def r;
r.detailed_name = o.detailed_name;
r.hover = o.hover;
r.comments = o.comments;
r.spell = o.spell;
r.bases = Convert(o.bases);
r.funcs = Convert(o.funcs);
r.types = Convert(o.types);
r.vars = Convert(o.vars);
r.bases = convert(o.bases);
r.funcs = convert(o.funcs);
r.types = convert(o.types);
r.vars = convert(o.vars);
r.alias_of = o.alias_of;
// no file_id
r.qual_name_offset = o.qual_name_offset;
@ -114,7 +114,7 @@ QueryType::Def Convert(const IndexType::Def &o) {
return r;
}
IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
IndexUpdate IndexUpdate::createDelta(IndexFile *previous, IndexFile *current) {
IndexUpdate r;
static IndexFile empty(current->path, "<empty>", false);
if (previous)
@ -127,7 +127,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : previous->usr2func) {
auto &func = it.second;
if (func.def.detailed_name[0])
r.funcs_removed.emplace_back(func.usr, Convert(func.def));
r.funcs_removed.emplace_back(func.usr, convert(func.def));
r.funcs_declarations[func.usr].first = std::move(func.declarations);
r.funcs_uses[func.usr].first = std::move(func.uses);
r.funcs_derived[func.usr].first = std::move(func.derived);
@ -135,7 +135,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : current->usr2func) {
auto &func = it.second;
if (func.def.detailed_name[0])
r.funcs_def_update.emplace_back(it.first, Convert(func.def));
r.funcs_def_update.emplace_back(it.first, convert(func.def));
r.funcs_declarations[func.usr].second = std::move(func.declarations);
r.funcs_uses[func.usr].second = std::move(func.uses);
r.funcs_derived[func.usr].second = std::move(func.derived);
@ -145,7 +145,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : previous->usr2type) {
auto &type = it.second;
if (type.def.detailed_name[0])
r.types_removed.emplace_back(type.usr, Convert(type.def));
r.types_removed.emplace_back(type.usr, convert(type.def));
r.types_declarations[type.usr].first = std::move(type.declarations);
r.types_uses[type.usr].first = std::move(type.uses);
r.types_derived[type.usr].first = std::move(type.derived);
@ -154,7 +154,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : current->usr2type) {
auto &type = it.second;
if (type.def.detailed_name[0])
r.types_def_update.emplace_back(it.first, Convert(type.def));
r.types_def_update.emplace_back(it.first, convert(type.def));
r.types_declarations[type.usr].second = std::move(type.declarations);
r.types_uses[type.usr].second = std::move(type.uses);
r.types_derived[type.usr].second = std::move(type.derived);
@ -177,7 +177,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
r.vars_uses[var.usr].second = std::move(var.uses);
}
r.files_def_update = BuildFileDefUpdate(std::move(*current));
r.files_def_update = buildFileDefUpdate(std::move(*current));
return r;
}
@ -193,15 +193,15 @@ void DB::clear() {
}
template <typename Def>
void DB::RemoveUsrs(Kind kind, int file_id,
void DB::removeUsrs(Kind kind, int file_id,
const std::vector<std::pair<Usr, Def>> &to_remove) {
switch (kind) {
case Kind::Func: {
for (auto &[usr, _] : to_remove) {
// FIXME
if (!HasFunc(usr))
if (!hasFunc(usr))
continue;
QueryFunc &func = Func(usr);
QueryFunc &func = getFunc(usr);
auto it = llvm::find_if(func.def, [=](const QueryFunc::Def &def) {
return def.file_id == file_id;
});
@ -213,9 +213,9 @@ void DB::RemoveUsrs(Kind kind, int file_id,
case Kind::Type: {
for (auto &[usr, _] : to_remove) {
// FIXME
if (!HasType(usr))
if (!hasType(usr))
continue;
QueryType &type = Type(usr);
QueryType &type = getType(usr);
auto it = llvm::find_if(type.def, [=](const QueryType::Def &def) {
return def.file_id == file_id;
});
@ -227,9 +227,9 @@ void DB::RemoveUsrs(Kind kind, int file_id,
case Kind::Var: {
for (auto &[usr, _] : to_remove) {
// FIXME
if (!HasVar(usr))
if (!hasVar(usr))
continue;
QueryVar &var = Var(usr);
QueryVar &var = getVar(usr);
auto it = llvm::find_if(var.def, [=](const QueryVar::Def &def) {
return def.file_id == file_id;
});
@ -243,24 +243,24 @@ void DB::RemoveUsrs(Kind kind, int file_id,
}
}
void DB::ApplyIndexUpdate(IndexUpdate *u) {
void DB::applyIndexUpdate(IndexUpdate *u) {
#define REMOVE_ADD(C, F) \
for (auto &it : u->C##s_##F) { \
auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \
if (R.second) { \
auto r = C##_usr.try_emplace({it.first}, C##_usr.size()); \
if (r.second) { \
C##s.emplace_back(); \
C##s.back().usr = it.first; \
} \
auto &entity = C##s[R.first->second]; \
RemoveRange(entity.F, it.second.first); \
AddRange(entity.F, it.second.second); \
auto &entity = C##s[r.first->second]; \
removeRange(entity.F, it.second.first); \
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);
prev_lid2file_id[lid] = getFileId(path);
for (auto &[lid, path] : u->lid2path) {
int file_id = GetFileId(path);
int file_id = getFileId(path);
lid2file_id[lid] = file_id;
if (!files[file_id].def) {
files[file_id].def = QueryFile::Def();
@ -269,7 +269,7 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
}
// References (Use &use) in this function are important to update file_id.
auto Ref = [&](std::unordered_map<int, int> &lid2fid, Usr usr, Kind kind,
auto ref = [&](std::unordered_map<int, int> &lid2fid, Usr usr, Kind kind,
Use &use, int delta) {
use.file_id =
use.file_id == -1 ? u->file_id : lid2fid.find(use.file_id)->second;
@ -280,7 +280,7 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
if (!v)
files[use.file_id].symbol2refcnt.erase(sym);
};
auto RefDecl = [&](std::unordered_map<int, int> &lid2fid, Usr usr, Kind kind,
auto refDecl = [&](std::unordered_map<int, int> &lid2fid, Usr usr, Kind kind,
DeclRef &dr, int delta) {
dr.file_id =
dr.file_id == -1 ? u->file_id : lid2fid.find(dr.file_id)->second;
@ -292,16 +292,16 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
files[dr.file_id].symbol2refcnt.erase(sym);
};
auto UpdateUses =
auto updateUses =
[&](Usr usr, Kind kind,
llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
auto &entities, auto &p, bool hint_implicit) {
auto R = entity_usr.try_emplace(usr, entity_usr.size());
if (R.second) {
auto r = entity_usr.try_emplace(usr, entity_usr.size());
if (r.second) {
entities.emplace_back();
entities.back().usr = usr;
}
auto &entity = entities[R.first->second];
auto &entity = entities[r.first->second];
for (Use &use : p.first) {
if (hint_implicit && use.role & Role::Implicit) {
// Make ranges of implicit function calls larger (spanning one more
@ -312,25 +312,25 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
use.range.start.column--;
use.range.end.column++;
}
Ref(prev_lid2file_id, usr, kind, use, -1);
ref(prev_lid2file_id, usr, kind, use, -1);
}
RemoveRange(entity.uses, p.first);
removeRange(entity.uses, p.first);
for (Use &use : p.second) {
if (hint_implicit && use.role & Role::Implicit) {
if (use.range.start.column > 0)
use.range.start.column--;
use.range.end.column++;
}
Ref(lid2file_id, usr, kind, use, 1);
ref(lid2file_id, usr, kind, use, 1);
}
AddRange(entity.uses, p.second);
addRange(entity.uses, p.second);
};
if (u->files_removed)
files[name2file_id[LowerPathIfInsensitive(*u->files_removed)]].def =
files[name2file_id[lowerPathIfInsensitive(*u->files_removed)]].def =
std::nullopt;
u->file_id =
u->files_def_update ? Update(std::move(*u->files_def_update)) : -1;
u->files_def_update ? update(std::move(*u->files_def_update)) : -1;
const double grow = 1.3;
size_t t;
@ -342,19 +342,19 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
}
for (auto &[usr, def] : u->funcs_removed)
if (def.spell)
RefDecl(prev_lid2file_id, usr, Kind::Func, *def.spell, -1);
RemoveUsrs(Kind::Func, u->file_id, u->funcs_removed);
Update(lid2file_id, u->file_id, std::move(u->funcs_def_update));
refDecl(prev_lid2file_id, usr, Kind::Func, *def.spell, -1);
removeUsrs(Kind::Func, u->file_id, u->funcs_removed);
update(lid2file_id, u->file_id, std::move(u->funcs_def_update));
for (auto &[usr, del_add] : u->funcs_declarations) {
for (DeclRef &dr : del_add.first)
RefDecl(prev_lid2file_id, usr, Kind::Func, dr, -1);
refDecl(prev_lid2file_id, usr, Kind::Func, dr, -1);
for (DeclRef &dr : del_add.second)
RefDecl(lid2file_id, usr, Kind::Func, dr, 1);
refDecl(lid2file_id, usr, Kind::Func, dr, 1);
}
REMOVE_ADD(func, declarations);
REMOVE_ADD(func, derived);
for (auto &[usr, p] : u->funcs_uses)
UpdateUses(usr, Kind::Func, func_usr, funcs, p, true);
updateUses(usr, Kind::Func, func_usr, funcs, p, true);
if ((t = types.size() + u->types_hint) > types.capacity()) {
t = size_t(t * grow);
@ -363,20 +363,20 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
}
for (auto &[usr, def] : u->types_removed)
if (def.spell)
RefDecl(prev_lid2file_id, usr, Kind::Type, *def.spell, -1);
RemoveUsrs(Kind::Type, u->file_id, u->types_removed);
Update(lid2file_id, u->file_id, std::move(u->types_def_update));
refDecl(prev_lid2file_id, usr, Kind::Type, *def.spell, -1);
removeUsrs(Kind::Type, u->file_id, u->types_removed);
update(lid2file_id, u->file_id, std::move(u->types_def_update));
for (auto &[usr, del_add] : u->types_declarations) {
for (DeclRef &dr : del_add.first)
RefDecl(prev_lid2file_id, usr, Kind::Type, dr, -1);
refDecl(prev_lid2file_id, usr, Kind::Type, dr, -1);
for (DeclRef &dr : del_add.second)
RefDecl(lid2file_id, usr, Kind::Type, dr, 1);
refDecl(lid2file_id, usr, Kind::Type, dr, 1);
}
REMOVE_ADD(type, declarations);
REMOVE_ADD(type, derived);
REMOVE_ADD(type, instances);
for (auto &[usr, p] : u->types_uses)
UpdateUses(usr, Kind::Type, type_usr, types, p, false);
updateUses(usr, Kind::Type, type_usr, types, p, false);
if ((t = vars.size() + u->vars_hint) > vars.capacity()) {
t = size_t(t * grow);
@ -385,24 +385,24 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
}
for (auto &[usr, def] : u->vars_removed)
if (def.spell)
RefDecl(prev_lid2file_id, usr, Kind::Var, *def.spell, -1);
RemoveUsrs(Kind::Var, u->file_id, u->vars_removed);
Update(lid2file_id, u->file_id, std::move(u->vars_def_update));
refDecl(prev_lid2file_id, usr, Kind::Var, *def.spell, -1);
removeUsrs(Kind::Var, u->file_id, u->vars_removed);
update(lid2file_id, u->file_id, std::move(u->vars_def_update));
for (auto &[usr, del_add] : u->vars_declarations) {
for (DeclRef &dr : del_add.first)
RefDecl(prev_lid2file_id, usr, Kind::Var, dr, -1);
refDecl(prev_lid2file_id, usr, Kind::Var, dr, -1);
for (DeclRef &dr : del_add.second)
RefDecl(lid2file_id, usr, Kind::Var, dr, 1);
refDecl(lid2file_id, usr, Kind::Var, dr, 1);
}
REMOVE_ADD(var, declarations);
for (auto &[usr, p] : u->vars_uses)
UpdateUses(usr, Kind::Var, var_usr, vars, p, false);
updateUses(usr, Kind::Var, var_usr, vars, p, false);
#undef REMOVE_ADD
}
int DB::GetFileId(const std::string &path) {
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(path));
int DB::getFileId(const std::string &path) {
auto it = name2file_id.try_emplace(lowerPathIfInsensitive(path));
if (it.second) {
int id = files.size();
it.first->second = files.emplace_back().id = id;
@ -410,80 +410,80 @@ int DB::GetFileId(const std::string &path) {
return it.first->second;
}
int DB::Update(QueryFile::DefUpdate &&u) {
int file_id = GetFileId(u.first.path);
int DB::update(QueryFile::DefUpdate &&u) {
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,
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;
assert(def.detailed_name[0]);
u.second.file_id = file_id;
if (def.spell) {
AssignFileId(lid2file_id, file_id, *def.spell);
assignFileId(lid2file_id, file_id, *def.spell);
files[def.spell->file_id].symbol2refcnt[{
{def.spell->range, u.first, Kind::Func, def.spell->role},
def.spell->extent}]++;
}
auto R = func_usr.try_emplace({u.first}, func_usr.size());
if (R.second)
auto r = func_usr.try_emplace({u.first}, func_usr.size());
if (r.second)
funcs.emplace_back();
QueryFunc &existing = funcs[R.first->second];
QueryFunc &existing = funcs[r.first->second];
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));
}
}
void DB::Update(const Lid2file_id &lid2file_id, int file_id,
void DB::update(const Lid2file_id &lid2file_id, int file_id,
std::vector<std::pair<Usr, QueryType::Def>> &&us) {
for (auto &u : us) {
auto &def = u.second;
assert(def.detailed_name[0]);
u.second.file_id = file_id;
if (def.spell) {
AssignFileId(lid2file_id, file_id, *def.spell);
assignFileId(lid2file_id, file_id, *def.spell);
files[def.spell->file_id].symbol2refcnt[{
{def.spell->range, u.first, Kind::Type, def.spell->role},
def.spell->extent}]++;
}
auto R = type_usr.try_emplace({u.first}, type_usr.size());
if (R.second)
auto r = type_usr.try_emplace({u.first}, type_usr.size());
if (r.second)
types.emplace_back();
QueryType &existing = types[R.first->second];
QueryType &existing = types[r.first->second];
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));
}
}
void DB::Update(const Lid2file_id &lid2file_id, int file_id,
void DB::update(const Lid2file_id &lid2file_id, int file_id,
std::vector<std::pair<Usr, QueryVar::Def>> &&us) {
for (auto &u : us) {
auto &def = u.second;
assert(def.detailed_name[0]);
u.second.file_id = file_id;
if (def.spell) {
AssignFileId(lid2file_id, file_id, *def.spell);
assignFileId(lid2file_id, file_id, *def.spell);
files[def.spell->file_id].symbol2refcnt[{
{def.spell->range, u.first, Kind::Var, def.spell->role},
def.spell->extent}]++;
}
auto R = var_usr.try_emplace({u.first}, var_usr.size());
if (R.second)
auto r = var_usr.try_emplace({u.first}, var_usr.size());
if (r.second)
vars.emplace_back();
QueryVar &existing = vars[R.first->second];
QueryVar &existing = vars[r.first->second];
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));
}
}
std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) {
std::string_view DB::getSymbolName(SymbolIdx sym, bool qualified) {
Usr usr = sym.usr;
switch (sym.kind) {
default:
@ -493,22 +493,22 @@ std::string_view DB::GetSymbolName(SymbolIdx sym, bool qualified) {
return files[usr].def->path;
break;
case Kind::Func:
if (const auto *def = Func(usr).AnyDef())
return def->Name(qualified);
if (const auto *def = getFunc(usr).anyDef())
return def->name(qualified);
break;
case Kind::Type:
if (const auto *def = Type(usr).AnyDef())
return def->Name(qualified);
if (const auto *def = getType(usr).anyDef())
return def->name(qualified);
break;
case Kind::Var:
if (const auto *def = Var(usr).AnyDef())
return def->Name(qualified);
if (const auto *def = getVar(usr).anyDef())
return def->name(qualified);
break;
}
return "";
}
std::vector<uint8_t> DB::GetFileSet(const std::vector<std::string> &folders) {
std::vector<uint8_t> DB::getFileSet(const std::vector<std::string> &folders) {
if (folders.empty())
return std::vector<uint8_t>(files.size(), 1);
std::vector<uint8_t> file_set(files.size());
@ -528,7 +528,7 @@ std::vector<uint8_t> DB::GetFileSet(const std::vector<std::string> &folders) {
namespace {
// Computes roughly how long |range| is.
int ComputeRangeSize(const Range &range) {
int computeRangeSize(const Range &range) {
if (range.start.line != range.end.line)
return INT_MAX;
return range.end.column - range.start.column;
@ -536,7 +536,7 @@ int ComputeRangeSize(const Range &range) {
template <typename Q, typename C>
std::vector<Use>
GetDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
getDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
llvm::SmallVectorImpl<Q> &entities, const C &usrs) {
std::vector<Use> ret;
ret.reserve(usrs.size());
@ -554,29 +554,29 @@ GetDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
}
return ret;
}
}
} // namespace
Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym) {
Maybe<DeclRef> getDefinitionSpell(DB *db, SymbolIdx sym) {
Maybe<DeclRef> ret;
EachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.spell); });
eachEntityDef(db, sym, [&](const auto &def) { return !(ret = def.spell); });
return ret;
}
std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
return GetDeclarations(db->func_usr, db->funcs, usrs);
std::vector<Use> getFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
return getDeclarations(db->func_usr, db->funcs, usrs);
}
std::vector<Use> GetFuncDeclarations(DB *db, const Vec<Usr> &usrs) {
return GetDeclarations(db->func_usr, db->funcs, usrs);
std::vector<Use> getFuncDeclarations(DB *db, const Vec<Usr> &usrs) {
return getDeclarations(db->func_usr, db->funcs, usrs);
}
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
return GetDeclarations(db->type_usr, db->types, usrs);
std::vector<Use> getTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
return getDeclarations(db->type_usr, db->types, usrs);
}
std::vector<DeclRef> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
std::vector<DeclRef> getVarDeclarations(DB *db, const std::vector<Usr> &usrs,
unsigned kind) {
std::vector<DeclRef> ret;
ret.reserve(usrs.size());
for (Usr usr : usrs) {
QueryVar &var = db->Var(usr);
QueryVar &var = db->getVar(usr);
bool has_def = false;
for (auto &def : var.def)
if (def.spell) {
@ -601,22 +601,22 @@ std::vector<DeclRef> GetVarDeclarations(DB *db, const std::vector<Usr> &usrs,
return ret;
}
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym) {
std::vector<DeclRef> &getNonDefDeclarations(DB *db, SymbolIdx sym) {
static std::vector<DeclRef> empty;
switch (sym.kind) {
case Kind::Func:
return db->GetFunc(sym).declarations;
return db->getFunc(sym).declarations;
case Kind::Type:
return db->GetType(sym).declarations;
return db->getType(sym).declarations;
case Kind::Var:
return db->GetVar(sym).declarations;
return db->getVar(sym).declarations;
default:
break;
}
return empty;
}
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
std::vector<Use> getUsesForAllBases(DB *db, QueryFunc &root) {
std::vector<Use> ret;
std::vector<QueryFunc *> stack{&root};
std::unordered_set<Usr> seen;
@ -624,8 +624,8 @@ std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
while (!stack.empty()) {
QueryFunc &func = *stack.back();
stack.pop_back();
if (auto *def = func.AnyDef()) {
EachDefinedFunc(db, def->bases, [&](QueryFunc &func1) {
if (auto *def = func.anyDef()) {
eachDefinedFunc(db, def->bases, [&](QueryFunc &func1) {
if (!seen.count(func1.usr)) {
seen.insert(func1.usr);
stack.push_back(&func1);
@ -638,7 +638,7 @@ std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root) {
return ret;
}
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
std::vector<Use> getUsesForAllDerived(DB *db, QueryFunc &root) {
std::vector<Use> ret;
std::vector<QueryFunc *> stack{&root};
std::unordered_set<Usr> seen;
@ -646,7 +646,7 @@ std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
while (!stack.empty()) {
QueryFunc &func = *stack.back();
stack.pop_back();
EachDefinedFunc(db, func.derived, [&](QueryFunc &func1) {
eachDefinedFunc(db, func.derived, [&](QueryFunc &func1) {
if (!seen.count(func1.usr)) {
seen.insert(func1.usr);
stack.push_back(&func1);
@ -658,17 +658,16 @@ std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root) {
return ret;
}
std::optional<lsRange> GetLsRange(WorkingFile *wfile,
const Range &location) {
std::optional<lsRange> getLsRange(WorkingFile *wfile, const Range &location) {
if (!wfile || wfile->index_lines.empty())
return lsRange{Position{location.start.line, location.start.column},
Position{location.end.line, location.end.column}};
int start_column = location.start.column, end_column = location.end.column;
std::optional<int> start = wfile->GetBufferPosFromIndexPos(
std::optional<int> start = wfile->getBufferPosFromIndexPos(
location.start.line, &start_column, false);
std::optional<int> end = wfile->GetBufferPosFromIndexPos(
location.end.line, &end_column, true);
std::optional<int> end =
wfile->getBufferPosFromIndexPos(location.end.line, &end_column, true);
if (!start || !end)
return std::nullopt;
@ -686,61 +685,61 @@ std::optional<lsRange> GetLsRange(WorkingFile *wfile,
return lsRange{Position{*start, start_column}, Position{*end, end_column}};
}
DocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path) {
DocumentUri getLsDocumentUri(DB *db, int file_id, std::string *path) {
QueryFile &file = db->files[file_id];
if (file.def) {
*path = file.def->path;
return DocumentUri::FromPath(*path);
return DocumentUri::fromPath(*path);
} else {
*path = "";
return DocumentUri::FromPath("");
return DocumentUri::fromPath("");
}
}
DocumentUri GetLsDocumentUri(DB *db, int file_id) {
DocumentUri getLsDocumentUri(DB *db, int file_id) {
QueryFile &file = db->files[file_id];
if (file.def) {
return DocumentUri::FromPath(file.def->path);
return DocumentUri::fromPath(file.def->path);
} else {
return DocumentUri::FromPath("");
return DocumentUri::fromPath("");
}
}
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use) {
std::optional<Location> getLsLocation(DB *db, WorkingFiles *wfiles, Use use) {
std::string path;
DocumentUri uri = GetLsDocumentUri(db, use.file_id, &path);
std::optional<lsRange> range = GetLsRange(wfiles->GetFile(path), use.range);
DocumentUri uri = getLsDocumentUri(db, use.file_id, &path);
std::optional<lsRange> range = getLsRange(wfiles->getFile(path), use.range);
if (!range)
return std::nullopt;
return Location{uri, *range};
}
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
std::optional<Location> getLsLocation(DB *db, WorkingFiles *wfiles,
SymbolRef sym, int file_id) {
return GetLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
return getLsLocation(db, wfiles, Use{{sym.range, sym.role}, file_id});
}
LocationLink GetLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr) {
LocationLink getLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr) {
std::string path;
DocumentUri uri = GetLsDocumentUri(db, dr.file_id, &path);
if (auto range = GetLsRange(wfiles->GetFile(path), dr.range))
if (auto extent = GetLsRange(wfiles->GetFile(path), dr.extent)) {
DocumentUri uri = getLsDocumentUri(db, dr.file_id, &path);
if (auto range = getLsRange(wfiles->getFile(path), dr.range))
if (auto extent = getLsRange(wfiles->getFile(path), dr.extent)) {
LocationLink ret;
ret.targetUri = uri.raw_uri;
ret.targetSelectionRange = *range;
ret.targetRange = extent->Includes(*range) ? *extent : *range;
ret.targetRange = extent->includes(*range) ? *extent : *range;
return ret;
}
return {};
}
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
SymbolKind getSymbolKind(DB *db, SymbolIdx sym) {
SymbolKind ret;
if (sym.kind == Kind::File)
ret = SymbolKind::File;
else {
ret = SymbolKind::Unknown;
WithEntity(db, sym, [&](const auto &entity) {
withEntity(db, sym, [&](const auto &entity) {
for (auto &def : entity.def) {
ret = def.kind;
break;
@ -750,13 +749,13 @@ SymbolKind GetSymbolKind(DB *db, SymbolIdx sym) {
return ret;
}
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
std::optional<SymbolInformation> getSymbolInfo(DB *db, SymbolIdx sym,
bool detailed) {
switch (sym.kind) {
case Kind::Invalid:
break;
case Kind::File: {
QueryFile &file = db->GetFile(sym);
QueryFile &file = db->getFile(sym);
if (!file.def)
break;
@ -767,11 +766,11 @@ std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
}
default: {
SymbolInformation info;
EachEntityDef(db, sym, [&](const auto &def) {
eachEntityDef(db, sym, [&](const auto &def) {
if (detailed)
info.name = def.detailed_name;
else
info.name = def.Name(true);
info.name = def.name(true);
info.kind = def.kind;
return false;
});
@ -782,14 +781,14 @@ std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
return std::nullopt;
}
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
std::vector<SymbolRef> findSymbolsAtLocation(WorkingFile *wfile,
QueryFile *file, Position &ls_pos,
bool smallest) {
std::vector<SymbolRef> symbols;
// If multiVersion > 0, index may not exist and thus index_lines is empty.
if (wfile && wfile->index_lines.size()) {
if (auto line = wfile->GetIndexPosFromBufferPos(
ls_pos.line, &ls_pos.character, false)) {
if (auto line = wfile->getIndexPosFromBufferPos(ls_pos.line,
&ls_pos.character, false)) {
ls_pos.line = *line;
} else {
ls_pos.line = -1;
@ -798,7 +797,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
}
for (auto [sym, refcnt] : file->symbol2refcnt)
if (refcnt > 0 && sym.range.Contains(ls_pos.line, ls_pos.character))
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
@ -815,7 +814,7 @@ std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *wfile,
std::sort(
symbols.begin(), symbols.end(),
[](const SymbolRef &a, const SymbolRef &b) {
int t = ComputeRangeSize(a.range) - ComputeRangeSize(b.range);
int t = computeRangeSize(a.range) - computeRangeSize(b.range);
if (t)
return t < 0;
// MacroExpansion

View File

@ -48,7 +48,7 @@ struct QueryFile {
template <typename Q, typename QDef> struct QueryEntity {
using Def = QDef;
Def *AnyDef() {
Def *anyDef() {
Def *ret = nullptr;
for (auto &i : static_cast<Q *>(this)->def) {
ret = &i;
@ -57,8 +57,8 @@ template <typename Q, typename QDef> struct QueryEntity {
}
return ret;
}
const Def *AnyDef() const {
return const_cast<QueryEntity *>(this)->AnyDef();
const Def *anyDef() const {
return const_cast<QueryEntity *>(this)->anyDef();
}
};
@ -93,7 +93,7 @@ struct QueryVar : QueryEntity<QueryVar, VarDef> {
struct IndexUpdate {
// Creates a new IndexUpdate based on the delta from previous to current. If
// no delta computation should be done just pass null for previous.
static IndexUpdate CreateDelta(IndexFile *previous, IndexFile *current);
static IndexUpdate createDelta(IndexFile *previous, IndexFile *current);
int file_id;
@ -154,87 +154,87 @@ struct DB {
void clear();
template <typename Def>
void RemoveUsrs(Kind kind, int file_id,
void removeUsrs(Kind kind, int file_id,
const std::vector<std::pair<Usr, Def>> &to_remove);
// Insert the contents of |update| into |db|.
void ApplyIndexUpdate(IndexUpdate *update);
int GetFileId(const std::string &path);
int Update(QueryFile::DefUpdate &&u);
void Update(const Lid2file_id &, int file_id,
void applyIndexUpdate(IndexUpdate *update);
int getFileId(const std::string &path);
int update(QueryFile::DefUpdate &&u);
void update(const Lid2file_id &, int file_id,
std::vector<std::pair<Usr, QueryType::Def>> &&us);
void Update(const Lid2file_id &, int file_id,
void update(const Lid2file_id &, int file_id,
std::vector<std::pair<Usr, QueryFunc::Def>> &&us);
void Update(const Lid2file_id &, int file_id,
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::vector<uint8_t> GetFileSet(const std::vector<std::string> &folders);
std::string_view getSymbolName(SymbolIdx sym, bool qualified);
std::vector<uint8_t> getFileSet(const std::vector<std::string> &folders);
bool HasFunc(Usr usr) const { return func_usr.count(usr); }
bool HasType(Usr usr) const { return type_usr.count(usr); }
bool HasVar(Usr usr) const { return var_usr.count(usr); }
bool hasFunc(Usr usr) const { return func_usr.count(usr); }
bool hasType(Usr usr) const { return type_usr.count(usr); }
bool hasVar(Usr usr) const { return var_usr.count(usr); }
QueryFunc &Func(Usr usr) { return funcs[func_usr[usr]]; }
QueryType &Type(Usr usr) { return types[type_usr[usr]]; }
QueryVar &Var(Usr usr) { return vars[var_usr[usr]]; }
QueryFunc &getFunc(Usr usr) { return funcs[func_usr[usr]]; }
QueryType &getType(Usr usr) { return types[type_usr[usr]]; }
QueryVar &getVar(Usr usr) { return vars[var_usr[usr]]; }
QueryFile &GetFile(SymbolIdx ref) { return files[ref.usr]; }
QueryFunc &GetFunc(SymbolIdx ref) { return Func(ref.usr); }
QueryType &GetType(SymbolIdx ref) { return Type(ref.usr); }
QueryVar &GetVar(SymbolIdx ref) { return Var(ref.usr); }
QueryFile &getFile(SymbolIdx ref) { return files[ref.usr]; }
QueryFunc &getFunc(SymbolIdx ref) { return getFunc(ref.usr); }
QueryType &getType(SymbolIdx ref) { return getType(ref.usr); }
QueryVar &getVar(SymbolIdx ref) { return getVar(ref.usr); }
};
Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym);
Maybe<DeclRef> getDefinitionSpell(DB *db, SymbolIdx sym);
// Get defining declaration (if exists) or an arbitrary declaration (otherwise)
// for each id.
std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> GetFuncDeclarations(DB *, const Vec<Usr> &);
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
std::vector<DeclRef> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
std::vector<Use> getFuncDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> getFuncDeclarations(DB *, const Vec<Usr> &);
std::vector<Use> getTypeDeclarations(DB *, const std::vector<Usr> &);
std::vector<DeclRef> getVarDeclarations(DB *, const std::vector<Usr> &,
unsigned);
// Get non-defining declarations.
std::vector<DeclRef> &GetNonDefDeclarations(DB *db, SymbolIdx sym);
std::vector<DeclRef> &getNonDefDeclarations(DB *db, SymbolIdx sym);
std::vector<Use> GetUsesForAllBases(DB *db, QueryFunc &root);
std::vector<Use> GetUsesForAllDerived(DB *db, QueryFunc &root);
std::optional<lsRange> GetLsRange(WorkingFile *working_file,
std::vector<Use> getUsesForAllBases(DB *db, QueryFunc &root);
std::vector<Use> getUsesForAllDerived(DB *db, QueryFunc &root);
std::optional<lsRange> getLsRange(WorkingFile *working_file,
const Range &location);
DocumentUri GetLsDocumentUri(DB *db, int file_id, std::string *path);
DocumentUri GetLsDocumentUri(DB *db, int file_id);
DocumentUri getLsDocumentUri(DB *db, int file_id, std::string *path);
DocumentUri getLsDocumentUri(DB *db, int file_id);
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles, Use use);
std::optional<Location> GetLsLocation(DB *db, WorkingFiles *wfiles,
std::optional<Location> getLsLocation(DB *db, WorkingFiles *wfiles, Use use);
std::optional<Location> getLsLocation(DB *db, WorkingFiles *wfiles,
SymbolRef sym, int file_id);
LocationLink GetLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr);
LocationLink getLocationLink(DB *db, WorkingFiles *wfiles, DeclRef dr);
// Returns a symbol. The symbol will *NOT* have a location assigned.
std::optional<SymbolInformation> GetSymbolInfo(DB *db, SymbolIdx sym,
std::optional<SymbolInformation> getSymbolInfo(DB *db, SymbolIdx sym,
bool detailed);
std::vector<SymbolRef> FindSymbolsAtLocation(WorkingFile *working_file,
QueryFile *file,
Position &ls_pos,
std::vector<SymbolRef> findSymbolsAtLocation(WorkingFile *working_file,
QueryFile *file, Position &ls_pos,
bool smallest = false);
template <typename Fn> void WithEntity(DB *db, SymbolIdx sym, Fn &&fn) {
template <typename Fn> void withEntity(DB *db, SymbolIdx sym, Fn &&fn) {
switch (sym.kind) {
case Kind::Invalid:
case Kind::File:
break;
case Kind::Func:
fn(db->GetFunc(sym));
fn(db->getFunc(sym));
break;
case Kind::Type:
fn(db->GetType(sym));
fn(db->getType(sym));
break;
case Kind::Var:
fn(db->GetVar(sym));
fn(db->getVar(sym));
break;
}
}
template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
WithEntity(db, sym, [&](const auto &entity) {
template <typename Fn> void eachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
withEntity(db, sym, [&](const auto &entity) {
for (auto &def : entity.def)
if (!fn(def))
break;
@ -242,8 +242,8 @@ template <typename Fn> void EachEntityDef(DB *db, SymbolIdx sym, Fn &&fn) {
}
template <typename Fn>
void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
WithEntity(db, sym, [&](const auto &entity) {
void eachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
withEntity(db, sym, [&](const auto &entity) {
for (Use use : entity.uses)
fn(use);
if (include_decl) {
@ -256,12 +256,12 @@ void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
});
}
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym);
SymbolKind getSymbolKind(DB *db, SymbolIdx sym);
template <typename C, typename Fn>
void EachDefinedFunc(DB *db, const C &usrs, Fn &&fn) {
void eachDefinedFunc(DB *db, const C &usrs, Fn &&fn) {
for (Usr usr : usrs) {
auto &obj = db->Func(usr);
auto &obj = db->getFunc(usr);
if (!obj.def.empty())
fn(obj);
}

View File

@ -56,16 +56,16 @@ struct ProxyFileSystem : FileSystem {
FileSystem &getUnderlyingFS() { return *FS; }
IntrusiveRefCntPtr<FileSystem> FS;
};
}
} // namespace clang::vfs
#endif
namespace ccls {
TextEdit ToTextEdit(const clang::SourceManager &SM, const clang::LangOptions &L,
const clang::FixItHint &FixIt) {
TextEdit toTextEdit(const clang::SourceManager &sm, const clang::LangOptions &l,
const clang::FixItHint &fixIt) {
TextEdit edit;
edit.newText = FixIt.CodeToInsert;
auto r = FromCharSourceRange(SM, L, FixIt.RemoveRange);
edit.newText = fixIt.CodeToInsert;
auto r = fromCharSourceRange(sm, l, fixIt.RemoveRange);
edit.range =
lsRange{{r.start.line, r.start.column}, {r.end.line, r.end.column}};
return edit;
@ -74,202 +74,202 @@ TextEdit ToTextEdit(const clang::SourceManager &SM, const clang::LangOptions &L,
using IncludeStructure = std::vector<std::pair<std::string, int64_t>>;
struct PreambleStatCache {
llvm::StringMap<ErrorOr<llvm::vfs::Status>> Cache;
llvm::StringMap<ErrorOr<llvm::vfs::Status>> cache;
void Update(Twine Path, ErrorOr<llvm::vfs::Status> S) {
Cache.try_emplace(Path.str(), std::move(S));
void update(Twine path, ErrorOr<llvm::vfs::Status> s) {
cache.try_emplace(path.str(), std::move(s));
}
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
Producer(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
producer(IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs) {
struct VFS : llvm::vfs::ProxyFileSystem {
PreambleStatCache &Cache;
PreambleStatCache &cache;
VFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
PreambleStatCache &Cache)
: ProxyFileSystem(std::move(FS)), Cache(Cache) {}
VFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
PreambleStatCache &cache)
: ProxyFileSystem(std::move(fs)), cache(cache) {}
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>>
openFileForRead(const Twine &Path) override {
auto File = getUnderlyingFS().openFileForRead(Path);
if (!File || !*File)
return File;
Cache.Update(Path, File->get()->status());
return File;
openFileForRead(const Twine &path) override {
auto file = getUnderlyingFS().openFileForRead(path);
if (!file || !*file)
return file;
cache.update(path, file->get()->status());
return file;
}
llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
auto S = getUnderlyingFS().status(Path);
Cache.Update(Path, S);
return S;
llvm::ErrorOr<llvm::vfs::Status> status(const Twine &path) override {
auto s = getUnderlyingFS().status(path);
cache.update(path, s);
return s;
}
};
return new VFS(std::move(FS), *this);
return new VFS(std::move(fs), *this);
}
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
Consumer(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
consumer(IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs) {
struct VFS : llvm::vfs::ProxyFileSystem {
const PreambleStatCache &Cache;
VFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const PreambleStatCache &Cache)
: ProxyFileSystem(std::move(FS)), Cache(Cache) {}
llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
auto I = Cache.Cache.find(Path.str());
if (I != Cache.Cache.end())
return I->getValue();
return getUnderlyingFS().status(Path);
const PreambleStatCache &cache;
VFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
const PreambleStatCache &cache)
: ProxyFileSystem(std::move(fs)), cache(cache) {}
llvm::ErrorOr<llvm::vfs::Status> status(const Twine &path) override {
auto i = cache.cache.find(path.str());
if (i != cache.cache.end())
return i->getValue();
return getUnderlyingFS().status(path);
}
};
return new VFS(std::move(FS), *this);
return new VFS(std::move(fs), *this);
}
};
struct PreambleData {
PreambleData(clang::PrecompiledPreamble P, IncludeStructure includes,
PreambleData(clang::PrecompiledPreamble p, IncludeStructure includes,
std::vector<Diag> diags,
std::unique_ptr<PreambleStatCache> stat_cache)
: Preamble(std::move(P)), includes(std::move(includes)),
: preamble(std::move(p)), includes(std::move(includes)),
diags(std::move(diags)), stat_cache(std::move(stat_cache)) {}
clang::PrecompiledPreamble Preamble;
clang::PrecompiledPreamble preamble;
IncludeStructure includes;
std::vector<Diag> diags;
std::unique_ptr<PreambleStatCache> stat_cache;
};
namespace {
bool LocationInRange(SourceLocation L, CharSourceRange R,
const SourceManager &M) {
assert(R.isCharRange());
if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
M.getFileID(R.getBegin()) != M.getFileID(L))
bool locationInRange(SourceLocation l, CharSourceRange r,
const SourceManager &m) {
assert(r.isCharRange());
if (!r.isValid() || m.getFileID(r.getBegin()) != m.getFileID(r.getEnd()) ||
m.getFileID(r.getBegin()) != m.getFileID(l))
return false;
return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
return l != r.getEnd() && m.isPointWithin(l, r.getBegin(), r.getEnd());
}
CharSourceRange DiagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
auto &M = D.getSourceManager();
auto Loc = M.getFileLoc(D.getLocation());
CharSourceRange diagnosticRange(const clang::Diagnostic &d,
const LangOptions &l) {
auto &m = d.getSourceManager();
auto loc = m.getFileLoc(d.getLocation());
// Accept the first range that contains the location.
for (const auto &CR : D.getRanges()) {
auto R = Lexer::makeFileCharRange(CR, M, L);
if (LocationInRange(Loc, R, M))
return R;
for (const auto &cr : d.getRanges()) {
auto r = Lexer::makeFileCharRange(cr, m, l);
if (locationInRange(loc, r, m))
return r;
}
// The range may be given as a fixit hint instead.
for (const auto &F : D.getFixItHints()) {
auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
if (LocationInRange(Loc, R, M))
return R;
for (const auto &f : d.getFixItHints()) {
auto r = Lexer::makeFileCharRange(f.RemoveRange, m, l);
if (locationInRange(loc, r, m))
return r;
}
// If no suitable range is found, just use the token at the location.
auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L);
if (!R.isValid()) // Fall back to location only, let the editor deal with it.
R = CharSourceRange::getCharRange(Loc);
return R;
auto r = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(loc), m, l);
if (!r.isValid()) // Fall back to location only, let the editor deal with it.
r = CharSourceRange::getCharRange(loc);
return r;
}
class StoreInclude : public PPCallbacks {
const SourceManager &SM;
const SourceManager &sm;
IncludeStructure &out;
DenseSet<const FileEntry *> Seen;
DenseSet<const FileEntry *> seen;
public:
StoreInclude(const SourceManager &SM, IncludeStructure &out)
: SM(SM), out(out) {}
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
StringRef FileName, bool IsAngled,
CharSourceRange FilenameRange, const FileEntry *File,
StringRef SearchPath, StringRef RelativePath,
const clang::Module *Imported,
SrcMgr::CharacteristicKind FileKind) override {
(void)SM;
if (File && Seen.insert(File).second)
out.emplace_back(PathFromFileEntry(*File), File->getModificationTime());
StoreInclude(const SourceManager &sm, IncludeStructure &out)
: sm(sm), out(out) {}
void InclusionDirective(SourceLocation hashLoc, const Token &includeTok,
StringRef fileName, bool isAngled,
CharSourceRange filenameRange, const FileEntry *file,
StringRef searchPath, StringRef relativePath,
const clang::Module *imported,
SrcMgr::CharacteristicKind fileKind) override {
(void)sm;
if (file && seen.insert(file).second)
out.emplace_back(pathFromFileEntry(*file), file->getModificationTime());
}
};
class CclsPreambleCallbacks : public PreambleCallbacks {
public:
void BeforeExecute(CompilerInstance &CI) override {
SM = &CI.getSourceManager();
void BeforeExecute(CompilerInstance &ci) override {
sm = &ci.getSourceManager();
}
std::unique_ptr<PPCallbacks> createPPCallbacks() override {
return std::make_unique<StoreInclude>(*SM, includes);
return std::make_unique<StoreInclude>(*sm, includes);
}
SourceManager *SM = nullptr;
SourceManager *sm = nullptr;
IncludeStructure includes;
};
class StoreDiags : public DiagnosticConsumer {
const LangOptions *LangOpts;
const LangOptions *langOpts;
std::optional<Diag> last;
std::vector<Diag> output;
std::string path;
std::unordered_map<unsigned, bool> FID2concerned;
void Flush() {
std::unordered_map<unsigned, bool> fID2concerned;
void flush() {
if (!last)
return;
bool mentions = last->concerned || last->edits.size();
if (!mentions)
for (auto &N : last->notes)
if (N.concerned)
for (auto &n : last->notes)
if (n.concerned)
mentions = true;
if (mentions)
output.push_back(std::move(*last));
last.reset();
}
public:
StoreDiags(std::string path) : path(std::move(path)) {}
std::vector<Diag> Take() {
return std::move(output);
}
bool IsConcerned(const SourceManager &SM, SourceLocation L) {
FileID FID = SM.getFileID(L);
auto it = FID2concerned.try_emplace(FID.getHashValue());
std::vector<Diag> take() { return std::move(output); }
bool isConcerned(const SourceManager &sm, SourceLocation l) {
FileID fid = sm.getFileID(l);
auto it = fID2concerned.try_emplace(fid.getHashValue());
if (it.second) {
const FileEntry *FE = SM.getFileEntryForID(FID);
it.first->second = FE && PathFromFileEntry(*FE) == path;
const FileEntry *fe = sm.getFileEntryForID(fid);
it.first->second = fe && pathFromFileEntry(*fe) == path;
}
return it.first->second;
}
void BeginSourceFile(const LangOptions &Opts, const Preprocessor *) override {
LangOpts = &Opts;
void BeginSourceFile(const LangOptions &opts, const Preprocessor *) override {
langOpts = &opts;
}
void EndSourceFile() override {
Flush();
}
void HandleDiagnostic(DiagnosticsEngine::Level Level,
const clang::Diagnostic &Info) override {
DiagnosticConsumer::HandleDiagnostic(Level, Info);
SourceLocation L = Info.getLocation();
if (!L.isValid()) return;
const SourceManager &SM = Info.getSourceManager();
StringRef Filename = SM.getFilename(Info.getLocation());
bool concerned = SM.isWrittenInMainFile(L);
void EndSourceFile() override { flush(); }
void HandleDiagnostic(DiagnosticsEngine::Level level,
const clang::Diagnostic &info) override {
DiagnosticConsumer::HandleDiagnostic(level, info);
SourceLocation l = info.getLocation();
if (!l.isValid())
return;
const SourceManager &sm = info.getSourceManager();
StringRef filename = sm.getFilename(info.getLocation());
bool concerned = sm.isWrittenInMainFile(l);
auto fillDiagBase = [&](DiagBase &d) {
llvm::SmallString<64> Message;
Info.FormatDiagnostic(Message);
llvm::SmallString<64> message;
info.FormatDiagnostic(message);
d.range =
FromCharSourceRange(SM, *LangOpts, DiagnosticRange(Info, *LangOpts));
d.message = Message.str();
fromCharSourceRange(sm, *langOpts, diagnosticRange(info, *langOpts));
d.message = message.str();
d.concerned = concerned;
d.file = Filename;
d.level = Level;
d.category = DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
d.file = filename;
d.level = level;
d.category = DiagnosticIDs::getCategoryNumberForDiag(info.getID());
};
auto addFix = [&](bool SyntheticMessage) -> bool {
auto addFix = [&](bool syntheticMessage) -> bool {
if (!concerned)
return false;
for (const FixItHint &FixIt : Info.getFixItHints()) {
if (!IsConcerned(SM, FixIt.RemoveRange.getBegin()))
for (const FixItHint &fixIt : info.getFixItHints()) {
if (!isConcerned(sm, fixIt.RemoveRange.getBegin()))
return false;
last->edits.push_back(ToTextEdit(SM, *LangOpts, FixIt));
last->edits.push_back(toTextEdit(sm, *langOpts, fixIt));
}
return true;
};
if (Level == DiagnosticsEngine::Note || Level == DiagnosticsEngine::Remark) {
if (Info.getFixItHints().size()) {
if (level == DiagnosticsEngine::Note ||
level == DiagnosticsEngine::Remark) {
if (info.getFixItHints().size()) {
addFix(false);
} else {
Note &n = last->notes.emplace_back();
@ -278,112 +278,113 @@ public:
last->concerned = true;
}
} else {
Flush();
flush();
last = Diag();
fillDiagBase(*last);
if (!Info.getFixItHints().empty())
if (!info.getFixItHints().empty())
addFix(true);
}
}
};
std::unique_ptr<CompilerInstance> BuildCompilerInstance(
Session &session, std::unique_ptr<CompilerInvocation> CI,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, DiagnosticConsumer &DC,
const PreambleData *preamble, const std::string &main,
std::unique_ptr<llvm::MemoryBuffer> &Buf) {
std::unique_ptr<CompilerInstance>
buildCompilerInstance(Session &session, std::unique_ptr<CompilerInvocation> ci,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
DiagnosticConsumer &dc, const PreambleData *preamble,
const std::string &main,
std::unique_ptr<llvm::MemoryBuffer> &buf) {
if (preamble)
preamble->Preamble.OverridePreamble(*CI, FS, Buf.get());
preamble->preamble.OverridePreamble(*ci, fs, buf.get());
else
CI->getPreprocessorOpts().addRemappedFile(main, Buf.get());
ci->getPreprocessorOpts().addRemappedFile(main, buf.get());
auto Clang = std::make_unique<CompilerInstance>(session.PCH);
Clang->setInvocation(std::move(CI));
Clang->createDiagnostics(&DC, false);
Clang->setTarget(TargetInfo::CreateTargetInfo(
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
if (!Clang->hasTarget())
auto clang = std::make_unique<CompilerInstance>(session.pch);
clang->setInvocation(std::move(ci));
clang->createDiagnostics(&dc, false);
clang->setTarget(TargetInfo::CreateTargetInfo(
clang->getDiagnostics(), clang->getInvocation().TargetOpts));
if (!clang->hasTarget())
return nullptr;
Clang->getPreprocessorOpts().RetainRemappedFileBuffers = true;
clang->getPreprocessorOpts().RetainRemappedFileBuffers = true;
// Construct SourceManager with UserFilesAreVolatile: true because otherwise
// RequiresNullTerminator: true may cause out-of-bounds read when a file is
// mmap'ed but is saved concurrently.
#if LLVM_VERSION_MAJOR >= 9 // rC357037
Clang->createFileManager(FS);
clang->createFileManager(fs);
#else
Clang->setVirtualFileSystem(FS);
Clang->createFileManager();
clang->setVirtualFileSystem(fs);
clang->createFileManager();
#endif
Clang->setSourceManager(new SourceManager(Clang->getDiagnostics(),
Clang->getFileManager(), true));
auto &IS = Clang->getFrontendOpts().Inputs;
if (IS.size()) {
assert(IS[0].isFile());
IS[0] = FrontendInputFile(main, IS[0].getKind(), IS[0].isSystem());
clang->setSourceManager(new SourceManager(clang->getDiagnostics(),
clang->getFileManager(), true));
auto &isec = clang->getFrontendOpts().Inputs;
if (isec.size()) {
assert(isec[0].isFile());
isec[0] = FrontendInputFile(main, isec[0].getKind(), isec[0].isSystem());
}
return Clang;
return clang;
}
bool Parse(CompilerInstance &Clang) {
SyntaxOnlyAction Action;
if (!Action.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0]))
bool parse(CompilerInstance &clang) {
SyntaxOnlyAction action;
if (!action.BeginSourceFile(clang, clang.getFrontendOpts().Inputs[0]))
return false;
#if LLVM_VERSION_MAJOR >= 9 // rL364464
if (llvm::Error E = Action.Execute()) {
llvm::consumeError(std::move(E));
if (llvm::Error e = action.Execute()) {
llvm::consumeError(std::move(e));
return false;
}
#else
if (!Action.Execute())
if (!action.Execute())
return false;
#endif
Action.EndSourceFile();
action.EndSourceFile();
return true;
}
void BuildPreamble(Session &session, CompilerInvocation &CI,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
void buildPreamble(Session &session, CompilerInvocation &ci,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs,
const SemaManager::PreambleTask &task,
std::unique_ptr<PreambleStatCache> stat_cache) {
std::shared_ptr<PreambleData> OldP = session.GetPreamble();
std::string content = session.wfiles->GetContent(task.path);
std::unique_ptr<llvm::MemoryBuffer> Buf =
std::shared_ptr<PreambleData> oldP = session.getPreamble();
std::string content = session.wfiles->getContent(task.path);
std::unique_ptr<llvm::MemoryBuffer> buf =
llvm::MemoryBuffer::getMemBuffer(content);
auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), Buf.get(), 0);
if (!task.from_diag && OldP &&
OldP->Preamble.CanReuse(CI, Buf.get(), Bounds, FS.get()))
auto bounds = ComputePreambleBounds(*ci.getLangOpts(), buf.get(), 0);
if (!task.from_diag && oldP &&
oldP->preamble.CanReuse(ci, buf.get(), bounds, fs.get()))
return;
// -Werror makes warnings issued as errors, which stops parsing
// prematurely because of -ferror-limit=. This also works around the issue
// of -Werror + -Wunused-parameter in interaction with SkipFunctionBodies.
auto &Ws = CI.getDiagnosticOpts().Warnings;
Ws.erase(std::remove(Ws.begin(), Ws.end(), "error"), Ws.end());
CI.getDiagnosticOpts().IgnoreWarnings = false;
CI.getFrontendOpts().SkipFunctionBodies = true;
CI.getLangOpts()->CommentOpts.ParseAllComments = g_config->index.comments > 1;
CI.getLangOpts()->RetainCommentsFromSystemHeaders = true;
auto &ws = ci.getDiagnosticOpts().Warnings;
ws.erase(std::remove(ws.begin(), ws.end(), "error"), ws.end());
ci.getDiagnosticOpts().IgnoreWarnings = false;
ci.getFrontendOpts().SkipFunctionBodies = true;
ci.getLangOpts()->CommentOpts.ParseAllComments = g_config->index.comments > 1;
ci.getLangOpts()->RetainCommentsFromSystemHeaders = true;
StoreDiags DC(task.path);
IntrusiveRefCntPtr<DiagnosticsEngine> DE =
CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(), &DC, false);
if (OldP) {
StoreDiags dc(task.path);
IntrusiveRefCntPtr<DiagnosticsEngine> de =
CompilerInstance::createDiagnostics(&ci.getDiagnosticOpts(), &dc, false);
if (oldP) {
std::lock_guard lock(session.wfiles->mutex);
for (auto &include : OldP->includes)
if (WorkingFile *wf = session.wfiles->GetFileUnlocked(include.first))
CI.getPreprocessorOpts().addRemappedFile(
for (auto &include : oldP->includes)
if (WorkingFile *wf = session.wfiles->getFileUnlocked(include.first))
ci.getPreprocessorOpts().addRemappedFile(
include.first,
llvm::MemoryBuffer::getMemBufferCopy(wf->buffer_content).release());
}
CclsPreambleCallbacks PC;
if (auto NewPreamble = PrecompiledPreamble::Build(
CI, Buf.get(), Bounds, *DE, FS, session.PCH, true, PC)) {
assert(!CI.getPreprocessorOpts().RetainRemappedFileBuffers);
if (OldP) {
auto &old_includes = OldP->includes;
CclsPreambleCallbacks pc;
if (auto newPreamble = PrecompiledPreamble::Build(
ci, buf.get(), bounds, *de, fs, session.pch, true, pc)) {
assert(!ci.getPreprocessorOpts().RetainRemappedFileBuffers);
if (oldP) {
auto &old_includes = oldP->includes;
auto it = old_includes.begin();
std::sort(PC.includes.begin(), PC.includes.end());
for (auto &include : PC.includes)
std::sort(pc.includes.begin(), pc.includes.end());
for (auto &include : pc.includes)
if (include.second == 0) {
while (it != old_includes.end() && it->first < include.first)
++it;
@ -395,113 +396,113 @@ void BuildPreamble(Session &session, CompilerInvocation &CI,
std::lock_guard lock(session.mutex);
session.preamble = std::make_shared<PreambleData>(
std::move(*NewPreamble), std::move(PC.includes), DC.Take(),
std::move(*newPreamble), std::move(pc.includes), dc.take(),
std::move(stat_cache));
}
}
void *PreambleMain(void *manager_) {
void *preambleMain(void *manager_) {
auto *manager = static_cast<SemaManager *>(manager_);
set_thread_name("preamble");
while (true) {
SemaManager::PreambleTask task = manager->preamble_tasks.Dequeue();
if (pipeline::quit.load(std::memory_order_relaxed))
SemaManager::PreambleTask task = manager->preamble_tasks.dequeue();
if (pipeline::g_quit.load(std::memory_order_relaxed))
break;
bool created = false;
std::shared_ptr<Session> session =
manager->EnsureSession(task.path, &created);
manager->ensureSession(task.path, &created);
auto stat_cache = std::make_unique<PreambleStatCache>();
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
stat_cache->Producer(session->FS);
if (std::unique_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(task.path, session->file.args, FS))
BuildPreamble(*session, *CI, FS, task, std::move(stat_cache));
IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
stat_cache->producer(session->fs);
if (std::unique_ptr<CompilerInvocation> ci =
buildCompilerInvocation(task.path, session->file.args, fs))
buildPreamble(*session, *ci, fs, task, std::move(stat_cache));
if (task.comp_task) {
manager->comp_tasks.PushBack(std::move(task.comp_task));
manager->comp_tasks.pushBack(std::move(task.comp_task));
} else if (task.from_diag) {
manager->ScheduleDiag(task.path, 0);
manager->scheduleDiag(task.path, 0);
} else {
int debounce =
created ? g_config->diagnostics.onOpen : g_config->diagnostics.onSave;
if (debounce >= 0)
manager->ScheduleDiag(task.path, debounce);
manager->scheduleDiag(task.path, debounce);
}
}
pipeline::ThreadLeave();
pipeline::threadLeave();
return nullptr;
}
void *CompletionMain(void *manager_) {
void *completionMain(void *manager_) {
auto *manager = static_cast<SemaManager *>(manager_);
set_thread_name("comp");
while (true) {
std::unique_ptr<SemaManager::CompTask> task = manager->comp_tasks.Dequeue();
if (pipeline::quit.load(std::memory_order_relaxed))
std::unique_ptr<SemaManager::CompTask> task = manager->comp_tasks.dequeue();
if (pipeline::g_quit.load(std::memory_order_relaxed))
break;
// Drop older requests if we're not buffering.
while (g_config->completion.dropOldRequests &&
!manager->comp_tasks.IsEmpty()) {
!manager->comp_tasks.isEmpty()) {
manager->on_dropped_(task->id);
task->Consumer.reset();
task->consumer.reset();
task->on_complete(nullptr);
task = manager->comp_tasks.Dequeue();
if (pipeline::quit.load(std::memory_order_relaxed))
task = manager->comp_tasks.dequeue();
if (pipeline::g_quit.load(std::memory_order_relaxed))
break;
}
std::shared_ptr<Session> session = manager->EnsureSession(task->path);
std::shared_ptr<PreambleData> preamble = session->GetPreamble();
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
std::unique_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(task->path, session->file.args, FS);
if (!CI)
std::shared_ptr<Session> session = manager->ensureSession(task->path);
std::shared_ptr<PreambleData> preamble = session->getPreamble();
IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
preamble ? preamble->stat_cache->consumer(session->fs) : session->fs;
std::unique_ptr<CompilerInvocation> ci =
buildCompilerInvocation(task->path, session->file.args, fs);
if (!ci)
continue;
auto &FOpts = CI->getFrontendOpts();
FOpts.CodeCompleteOpts = task->CCOpts;
FOpts.CodeCompletionAt.FileName = task->path;
FOpts.CodeCompletionAt.Line = task->position.line + 1;
FOpts.CodeCompletionAt.Column = task->position.character + 1;
FOpts.SkipFunctionBodies = true;
CI->getLangOpts()->CommentOpts.ParseAllComments = true;
auto &fOpts = ci->getFrontendOpts();
fOpts.CodeCompleteOpts = task->cc_opts;
fOpts.CodeCompletionAt.FileName = task->path;
fOpts.CodeCompletionAt.Line = task->position.line + 1;
fOpts.CodeCompletionAt.Column = task->position.character + 1;
fOpts.SkipFunctionBodies = true;
ci->getLangOpts()->CommentOpts.ParseAllComments = true;
DiagnosticConsumer DC;
std::string content = manager->wfiles->GetContent(task->path);
auto Buf = llvm::MemoryBuffer::getMemBuffer(content);
PreambleBounds Bounds =
ComputePreambleBounds(*CI->getLangOpts(), Buf.get(), 0);
DiagnosticConsumer dc;
std::string content = manager->wfiles->getContent(task->path);
auto buf = llvm::MemoryBuffer::getMemBuffer(content);
PreambleBounds bounds =
ComputePreambleBounds(*ci->getLangOpts(), buf.get(), 0);
bool in_preamble =
GetOffsetForPosition({task->position.line, task->position.character},
content) < (int)Bounds.Size;
getOffsetForPosition({task->position.line, task->position.character},
content) < (int)bounds.Size;
if (in_preamble) {
preamble.reset();
} else if (preamble && Bounds.Size != preamble->Preamble.getBounds().Size) {
manager->preamble_tasks.PushBack({task->path, std::move(task), false},
} else if (preamble && bounds.Size != preamble->preamble.getBounds().Size) {
manager->preamble_tasks.pushBack({task->path, std::move(task), false},
true);
continue;
}
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
preamble.get(), task->path, Buf);
if (!Clang)
auto clang = buildCompilerInstance(*session, std::move(ci), fs, dc,
preamble.get(), task->path, buf);
if (!clang)
continue;
Clang->getPreprocessorOpts().SingleFileParseMode = in_preamble;
Clang->setCodeCompletionConsumer(task->Consumer.release());
if (!Parse(*Clang))
clang->getPreprocessorOpts().SingleFileParseMode = in_preamble;
clang->setCodeCompletionConsumer(task->consumer.release());
if (!parse(*clang))
continue;
task->on_complete(&Clang->getCodeCompletionConsumer());
task->on_complete(&clang->getCodeCompletionConsumer());
}
pipeline::ThreadLeave();
pipeline::threadLeave();
return nullptr;
}
llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
switch (Lvl) {
llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level lvl) {
switch (lvl) {
case DiagnosticsEngine::Ignored:
return "ignored";
case DiagnosticsEngine::Note:
@ -517,23 +518,23 @@ llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
}
}
void PrintDiag(llvm::raw_string_ostream &OS, const DiagBase &d) {
void printDiag(llvm::raw_string_ostream &os, const DiagBase &d) {
if (d.concerned)
OS << llvm::sys::path::filename(d.file);
os << llvm::sys::path::filename(d.file);
else
OS << d.file;
os << d.file;
auto pos = d.range.start;
OS << ":" << (pos.line + 1) << ":" << (pos.column + 1) << ":"
os << ":" << (pos.line + 1) << ":" << (pos.column + 1) << ":"
<< (d.concerned ? " " : "\n");
OS << diagLeveltoString(d.level) << ": " << d.message;
os << diagLeveltoString(d.level) << ": " << d.message;
}
void *DiagnosticMain(void *manager_) {
void *diagnosticMain(void *manager_) {
auto *manager = static_cast<SemaManager *>(manager_);
set_thread_name("diag");
while (true) {
SemaManager::DiagTask task = manager->diag_tasks.Dequeue();
if (pipeline::quit.load(std::memory_order_relaxed))
SemaManager::DiagTask task = manager->diag_tasks.dequeue();
if (pipeline::g_quit.load(std::memory_order_relaxed))
break;
int64_t wait = task.wait_until -
chrono::duration_cast<chrono::milliseconds>(
@ -543,47 +544,47 @@ void *DiagnosticMain(void *manager_) {
std::this_thread::sleep_for(
chrono::duration<int64_t, std::milli>(std::min(wait, task.debounce)));
std::shared_ptr<Session> session = manager->EnsureSession(task.path);
std::shared_ptr<PreambleData> preamble = session->GetPreamble();
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
std::shared_ptr<Session> session = manager->ensureSession(task.path);
std::shared_ptr<PreambleData> preamble = session->getPreamble();
IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
preamble ? preamble->stat_cache->consumer(session->fs) : session->fs;
if (preamble) {
bool rebuild = false;
{
std::lock_guard lock(manager->wfiles->mutex);
for (auto &include : preamble->includes)
if (WorkingFile *wf = manager->wfiles->GetFileUnlocked(include.first);
if (WorkingFile *wf = manager->wfiles->getFileUnlocked(include.first);
wf && include.second < wf->timestamp) {
include.second = wf->timestamp;
rebuild = true;
}
}
if (rebuild) {
manager->preamble_tasks.PushBack({task.path, nullptr, true}, true);
manager->preamble_tasks.pushBack({task.path, nullptr, true}, true);
continue;
}
}
std::unique_ptr<CompilerInvocation> CI =
BuildCompilerInvocation(task.path, session->file.args, FS);
if (!CI)
std::unique_ptr<CompilerInvocation> ci =
buildCompilerInvocation(task.path, session->file.args, fs);
if (!ci)
continue;
// If main file is a header, add -Wno-unused-function
if (lookupExtension(session->file.filename).second)
CI->getDiagnosticOpts().Warnings.push_back("no-unused-function");
CI->getDiagnosticOpts().IgnoreWarnings = false;
CI->getLangOpts()->SpellChecking = g_config->diagnostics.spellChecking;
StoreDiags DC(task.path);
std::string content = manager->wfiles->GetContent(task.path);
auto Buf = llvm::MemoryBuffer::getMemBuffer(content);
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
preamble.get(), task.path, Buf);
if (!Clang)
ci->getDiagnosticOpts().Warnings.push_back("no-unused-function");
ci->getDiagnosticOpts().IgnoreWarnings = false;
ci->getLangOpts()->SpellChecking = g_config->diagnostics.spellChecking;
StoreDiags dc(task.path);
std::string content = manager->wfiles->getContent(task.path);
auto buf = llvm::MemoryBuffer::getMemBuffer(content);
auto clang = buildCompilerInstance(*session, std::move(ci), fs, dc,
preamble.get(), task.path, buf);
if (!clang)
continue;
if (!Parse(*Clang))
if (!parse(*clang))
continue;
auto Fill = [](const DiagBase &d, Diagnostic &ret) {
auto fill = [](const DiagBase &d, Diagnostic &ret) {
ret.range = lsRange{{d.range.start.line, d.range.start.column},
{d.range.end.line, d.range.end.column}};
switch (d.level) {
@ -607,45 +608,45 @@ void *DiagnosticMain(void *manager_) {
return ret;
};
std::vector<Diag> diags = DC.Take();
if (std::shared_ptr<PreambleData> preamble = session->GetPreamble())
std::vector<Diag> diags = dc.take();
if (std::shared_ptr<PreambleData> preamble = session->getPreamble())
diags.insert(diags.end(), preamble->diags.begin(), preamble->diags.end());
std::vector<Diagnostic> ls_diags;
for (auto &d : diags) {
if (!d.concerned)
continue;
Diagnostic &ls_diag = ls_diags.emplace_back();
Fill(d, ls_diag);
fill(d, ls_diag);
ls_diag.fixits_ = d.edits;
if (g_config->client.diagnosticsRelatedInformation) {
ls_diag.message = d.message;
for (const Note &n : d.notes) {
SmallString<256> Str(n.file);
llvm::sys::path::remove_dots(Str, true);
Location loc{DocumentUri::FromPath(Str.str()),
SmallString<256> str(n.file);
llvm::sys::path::remove_dots(str, true);
Location loc{DocumentUri::fromPath(str.str()),
lsRange{{n.range.start.line, n.range.start.column},
{n.range.end.line, n.range.end.column}}};
ls_diag.relatedInformation.push_back({loc, n.message});
}
} else {
std::string buf;
llvm::raw_string_ostream OS(buf);
OS << d.message;
llvm::raw_string_ostream os(buf);
os << d.message;
for (const Note &n : d.notes) {
OS << "\n\n";
PrintDiag(OS, n);
os << "\n\n";
printDiag(os, n);
}
OS.flush();
os.flush();
ls_diag.message = std::move(buf);
for (const Note &n : d.notes) {
if (!n.concerned)
continue;
Diagnostic &ls_diag1 = ls_diags.emplace_back();
Fill(n, ls_diag1);
fill(n, ls_diag1);
buf.clear();
OS << n.message << "\n\n";
PrintDiag(OS, d);
OS.flush();
os << n.message << "\n\n";
printDiag(os, d);
os.flush();
ls_diag1.message = std::move(buf);
}
}
@ -653,18 +654,18 @@ void *DiagnosticMain(void *manager_) {
{
std::lock_guard lock(manager->wfiles->mutex);
if (WorkingFile *wf = manager->wfiles->GetFileUnlocked(task.path))
if (WorkingFile *wf = manager->wfiles->getFileUnlocked(task.path))
wf->diagnostics = ls_diags;
}
manager->on_diagnostic_(task.path, ls_diags);
}
pipeline::ThreadLeave();
pipeline::threadLeave();
return nullptr;
}
} // namespace
std::shared_ptr<PreambleData> Session::GetPreamble() {
std::shared_ptr<PreambleData> Session::getPreamble() {
std::lock_guard<std::mutex> lock(mutex);
return preamble;
}
@ -672,16 +673,16 @@ std::shared_ptr<PreambleData> Session::GetPreamble() {
SemaManager::SemaManager(Project *project, WorkingFiles *wfiles,
OnDiagnostic on_diagnostic, OnDropped on_dropped)
: project_(project), wfiles(wfiles), on_diagnostic_(on_diagnostic),
on_dropped_(on_dropped), PCH(std::make_shared<PCHContainerOperations>()) {
SpawnThread(ccls::PreambleMain, this);
SpawnThread(ccls::CompletionMain, this);
SpawnThread(ccls::DiagnosticMain, this);
on_dropped_(on_dropped), pch(std::make_shared<PCHContainerOperations>()) {
spawnThread(ccls::preambleMain, this);
spawnThread(ccls::completionMain, this);
spawnThread(ccls::diagnosticMain, this);
}
void SemaManager::ScheduleDiag(const std::string &path, int debounce) {
void SemaManager::scheduleDiag(const std::string &path, int debounce) {
static GroupMatch match(g_config->diagnostics.whitelist,
g_config->diagnostics.blacklist);
if (!match.Matches(path))
if (!match.matches(path))
return;
int64_t now = chrono::duration_cast<chrono::milliseconds>(
chrono::high_resolution_clock::now().time_since_epoch())
@ -698,31 +699,31 @@ void SemaManager::ScheduleDiag(const std::string &path, int debounce) {
}
}
if (flag)
diag_tasks.PushBack({path, now + debounce, debounce}, false);
diag_tasks.pushBack({path, now + debounce, debounce}, false);
}
void SemaManager::OnView(const std::string &path) {
void SemaManager::onView(const std::string &path) {
std::lock_guard lock(mutex);
if (!sessions.Get(path))
preamble_tasks.PushBack(PreambleTask{path}, true);
if (!sessions.get(path))
preamble_tasks.pushBack(PreambleTask{path}, true);
}
void SemaManager::OnSave(const std::string &path) {
preamble_tasks.PushBack(PreambleTask{path}, true);
void SemaManager::onSave(const std::string &path) {
preamble_tasks.pushBack(PreambleTask{path}, true);
}
void SemaManager::OnClose(const std::string &path) {
void SemaManager::onClose(const std::string &path) {
std::lock_guard lock(mutex);
sessions.Take(path);
sessions.take(path);
}
std::shared_ptr<ccls::Session>
SemaManager::EnsureSession(const std::string &path, bool *created) {
SemaManager::ensureSession(const std::string &path, bool *created) {
std::lock_guard lock(mutex);
std::shared_ptr<ccls::Session> session = sessions.Get(path);
std::shared_ptr<ccls::Session> session = sessions.get(path);
if (!session) {
session = std::make_shared<ccls::Session>(
project_->FindEntry(path, false, false), wfiles, PCH);
project_->findEntry(path, false, false), wfiles, pch);
std::string line;
if (LOG_V_ENABLED(1)) {
line = "\n ";
@ -730,22 +731,22 @@ SemaManager::EnsureSession(const std::string &path, bool *created) {
(line += ' ') += arg;
}
LOG_S(INFO) << "create session for " << path << line;
sessions.Insert(path, session);
sessions.insert(path, session);
if (created)
*created = true;
}
return session;
}
void SemaManager::Clear() {
void SemaManager::clear() {
LOG_S(INFO) << "clear all sessions";
std::lock_guard lock(mutex);
sessions.Clear();
sessions.clear();
}
void SemaManager::Quit() {
comp_tasks.PushBack(nullptr);
diag_tasks.PushBack({});
preamble_tasks.PushBack({});
void SemaManager::quit() {
comp_tasks.pushBack(nullptr);
diag_tasks.pushBack({});
preamble_tasks.pushBack({});
}
} // namespace ccls

View File

@ -37,12 +37,11 @@ struct Diag : DiagBase {
std::vector<TextEdit> edits;
};
TextEdit ToTextEdit(const clang::SourceManager &SM,
const clang::LangOptions &L,
TextEdit toTextEdit(const clang::SourceManager &SM, const clang::LangOptions &L,
const clang::FixItHint &FixIt);
template <typename K, typename V> struct LruCache {
std::shared_ptr<V> Get(const K &key) {
std::shared_ptr<V> get(const K &key) {
for (auto it = items.begin(); it != items.end(); ++it)
if (it->first == key) {
auto x = std::move(*it);
@ -52,7 +51,7 @@ template <typename K, typename V> struct LruCache {
}
return nullptr;
}
std::shared_ptr<V> Take(const K &key) {
std::shared_ptr<V> take(const K &key) {
for (auto it = items.begin(); it != items.end(); ++it)
if (it->first == key) {
auto x = std::move(it->second);
@ -61,13 +60,13 @@ template <typename K, typename V> struct LruCache {
}
return nullptr;
}
void Insert(const K &key, std::shared_ptr<V> value) {
void insert(const K &key, std::shared_ptr<V> value) {
if ((int)items.size() >= capacity)
items.pop_back();
items.emplace(items.begin(), key, std::move(value));
}
void Clear() { items.clear(); }
void SetCapacity(int cap) { capacity = cap; }
void clear() { items.clear(); }
void setCapacity(int cap) { capacity = cap; }
private:
std::vector<std::pair<K, std::shared_ptr<V>>> items;
@ -83,20 +82,20 @@ struct Session {
bool inferred = false;
// TODO share
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
llvm::vfs::getRealFileSystem();
std::shared_ptr<clang::PCHContainerOperations> PCH;
std::shared_ptr<clang::PCHContainerOperations> pch;
Session(const Project::Entry &file, WorkingFiles *wfiles,
std::shared_ptr<clang::PCHContainerOperations> PCH)
: file(file), wfiles(wfiles), PCH(PCH) {}
std::shared_ptr<clang::PCHContainerOperations> pch)
: file(file), wfiles(wfiles), pch(pch) {}
std::shared_ptr<PreambleData> GetPreamble();
std::shared_ptr<PreambleData> getPreamble();
};
struct SemaManager {
using OnDiagnostic = std::function<void(
std::string path, std::vector<Diagnostic> diagnostics)>;
using OnDiagnostic = std::function<void(std::string path,
std::vector<Diagnostic> diagnostics)>;
// If OptConsumer is nullptr, the request has been cancelled.
using OnComplete =
std::function<void(clang::CodeCompleteConsumer *OptConsumer)>;
@ -107,14 +106,14 @@ struct SemaManager {
const Position &position,
std::unique_ptr<clang::CodeCompleteConsumer> Consumer,
clang::CodeCompleteOptions CCOpts, const OnComplete &on_complete)
: id(id), path(path), position(position), Consumer(std::move(Consumer)),
CCOpts(CCOpts), on_complete(on_complete) {}
: id(id), path(path), position(position), consumer(std::move(Consumer)),
cc_opts(CCOpts), on_complete(on_complete) {}
RequestId id;
std::string path;
Position position;
std::unique_ptr<clang::CodeCompleteConsumer> Consumer;
clang::CodeCompleteOptions CCOpts;
std::unique_ptr<clang::CodeCompleteConsumer> consumer;
clang::CodeCompleteOptions cc_opts;
OnComplete on_complete;
};
struct DiagTask {
@ -131,14 +130,14 @@ struct SemaManager {
SemaManager(Project *project, WorkingFiles *wfiles,
OnDiagnostic on_diagnostic, OnDropped on_dropped);
void ScheduleDiag(const std::string &path, int debounce);
void OnView(const std::string &path);
void OnSave(const std::string &path);
void OnClose(const std::string &path);
std::shared_ptr<ccls::Session> EnsureSession(const std::string &path,
void scheduleDiag(const std::string &path, int debounce);
void onView(const std::string &path);
void onSave(const std::string &path);
void onClose(const std::string &path);
std::shared_ptr<ccls::Session> ensureSession(const std::string &path,
bool *created = nullptr);
void Clear();
void Quit();
void clear();
void quit();
// Global state.
Project *project_;
@ -156,24 +155,23 @@ struct SemaManager {
ThreadedQueue<DiagTask> diag_tasks;
ThreadedQueue<PreambleTask> preamble_tasks;
std::shared_ptr<clang::PCHContainerOperations> PCH;
std::shared_ptr<clang::PCHContainerOperations> pch;
};
// Cached completion information, so we can give fast completion results when
// the user erases a character. vscode will resend the completion request if
// that happens.
template <typename T>
struct CompleteConsumerCache {
template <typename T> struct CompleteConsumerCache {
std::mutex mutex;
std::string path;
Position position;
T result;
template <typename Fn> void WithLock(Fn &&fn) {
template <typename Fn> void withLock(Fn &&fn) {
std::lock_guard lock(mutex);
fn();
}
bool IsCacheValid(const std::string path, Position position) {
bool isCacheValid(const std::string path, Position position) {
std::lock_guard lock(mutex);
return this->path == path && this->position == position;
}

View File

@ -24,7 +24,7 @@ bool gTestOutputMode = false;
namespace ccls {
void JsonReader::IterArray(std::function<void()> fn) {
void JsonReader::iterArray(std::function<void()> fn) {
if (!m->IsArray())
throw std::invalid_argument("array");
// Use "0" to indicate any element for now.
@ -37,7 +37,7 @@ void JsonReader::IterArray(std::function<void()> fn) {
}
path_.pop_back();
}
void JsonReader::Member(const char *name, std::function<void()> fn) {
void JsonReader::member(const char *name, std::function<void()> fn) {
path_.push_back(name);
auto it = m->FindMember(name);
if (it != m->MemberEnd()) {
@ -48,9 +48,9 @@ void JsonReader::Member(const char *name, std::function<void()> fn) {
}
path_.pop_back();
}
bool JsonReader::IsNull() { return m->IsNull(); }
std::string JsonReader::GetString() { return m->GetString(); }
std::string JsonReader::GetPath() const {
bool JsonReader::isNull() { return m->IsNull(); }
std::string JsonReader::getString() { return m->GetString(); }
std::string JsonReader::getPath() const {
std::string ret;
for (auto &t : path_)
if (t[0] == '0') {
@ -64,157 +64,157 @@ std::string JsonReader::GetPath() const {
return ret;
}
void JsonWriter::StartArray() { m->StartArray(); }
void JsonWriter::EndArray() { m->EndArray(); }
void JsonWriter::StartObject() { m->StartObject(); }
void JsonWriter::EndObject() { m->EndObject(); }
void JsonWriter::Key(const char *name) { m->Key(name); }
void JsonWriter::Null() { m->Null(); }
void JsonWriter::Int(int v) { m->Int(v); }
void JsonWriter::String(const char *s) { m->String(s); }
void JsonWriter::String(const char *s, size_t len) { m->String(s, len); }
void JsonWriter::startArray() { m->StartArray(); }
void JsonWriter::endArray() { m->EndArray(); }
void JsonWriter::startObject() { m->StartObject(); }
void JsonWriter::endObject() { m->EndObject(); }
void JsonWriter::key(const char *name) { m->Key(name); }
void JsonWriter::null_() { m->Null(); }
void JsonWriter::int_(int v) { m->Int(v); }
void JsonWriter::string(const char *s) { m->String(s); }
void JsonWriter::string(const char *s, size_t len) { m->String(s, len); }
// clang-format off
void Reflect(JsonReader &vis, bool &v ) { if (!vis.m->IsBool()) throw std::invalid_argument("bool"); v = vis.m->GetBool(); }
void Reflect(JsonReader &vis, unsigned char &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("uint8_t"); v = (uint8_t)vis.m->GetInt(); }
void Reflect(JsonReader &vis, short &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("short"); v = (short)vis.m->GetInt(); }
void Reflect(JsonReader &vis, unsigned short &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("unsigned short"); v = (unsigned short)vis.m->GetInt(); }
void Reflect(JsonReader &vis, int &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("int"); v = vis.m->GetInt(); }
void Reflect(JsonReader &vis, unsigned &v ) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned"); v = (unsigned)vis.m->GetUint64(); }
void Reflect(JsonReader &vis, long &v ) { if (!vis.m->IsInt64()) throw std::invalid_argument("long"); v = (long)vis.m->GetInt64(); }
void Reflect(JsonReader &vis, unsigned long &v ) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned long"); v = (unsigned long)vis.m->GetUint64(); }
void Reflect(JsonReader &vis, long long &v ) { if (!vis.m->IsInt64()) throw std::invalid_argument("long long"); v = vis.m->GetInt64(); }
void Reflect(JsonReader &vis, unsigned long long &v) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned long long"); v = vis.m->GetUint64(); }
void Reflect(JsonReader &vis, double &v ) { if (!vis.m->IsDouble()) throw std::invalid_argument("double"); v = vis.m->GetDouble(); }
void Reflect(JsonReader &vis, const char *&v ) { if (!vis.m->IsString()) throw std::invalid_argument("string"); v = Intern(vis.GetString()); }
void Reflect(JsonReader &vis, std::string &v ) { if (!vis.m->IsString()) throw std::invalid_argument("string"); v = vis.GetString(); }
void reflect(JsonReader &vis, bool &v ) { if (!vis.m->IsBool()) throw std::invalid_argument("bool"); v = vis.m->GetBool(); }
void reflect(JsonReader &vis, unsigned char &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("uint8_t"); v = (uint8_t)vis.m->GetInt(); }
void reflect(JsonReader &vis, short &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("short"); v = (short)vis.m->GetInt(); }
void reflect(JsonReader &vis, unsigned short &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("unsigned short"); v = (unsigned short)vis.m->GetInt(); }
void reflect(JsonReader &vis, int &v ) { if (!vis.m->IsInt()) throw std::invalid_argument("int"); v = vis.m->GetInt(); }
void reflect(JsonReader &vis, unsigned &v ) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned"); v = (unsigned)vis.m->GetUint64(); }
void reflect(JsonReader &vis, long &v ) { if (!vis.m->IsInt64()) throw std::invalid_argument("long"); v = (long)vis.m->GetInt64(); }
void reflect(JsonReader &vis, unsigned long &v ) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned long"); v = (unsigned long)vis.m->GetUint64(); }
void reflect(JsonReader &vis, long long &v ) { if (!vis.m->IsInt64()) throw std::invalid_argument("long long"); v = vis.m->GetInt64(); }
void reflect(JsonReader &vis, unsigned long long &v) { if (!vis.m->IsUint64()) throw std::invalid_argument("unsigned long long"); v = vis.m->GetUint64(); }
void reflect(JsonReader &vis, double &v ) { if (!vis.m->IsDouble()) throw std::invalid_argument("double"); v = vis.m->GetDouble(); }
void reflect(JsonReader &vis, const char *&v ) { if (!vis.m->IsString()) throw std::invalid_argument("string"); v = intern(vis.getString()); }
void reflect(JsonReader &vis, std::string &v ) { if (!vis.m->IsString()) throw std::invalid_argument("string"); v = vis.getString(); }
void Reflect(JsonWriter &vis, bool &v ) { vis.m->Bool(v); }
void Reflect(JsonWriter &vis, unsigned char &v ) { vis.m->Int(v); }
void Reflect(JsonWriter &vis, short &v ) { vis.m->Int(v); }
void Reflect(JsonWriter &vis, unsigned short &v ) { vis.m->Int(v); }
void Reflect(JsonWriter &vis, int &v ) { vis.m->Int(v); }
void Reflect(JsonWriter &vis, unsigned &v ) { vis.m->Uint64(v); }
void Reflect(JsonWriter &vis, long &v ) { vis.m->Int64(v); }
void Reflect(JsonWriter &vis, unsigned long &v ) { vis.m->Uint64(v); }
void Reflect(JsonWriter &vis, long long &v ) { vis.m->Int64(v); }
void Reflect(JsonWriter &vis, unsigned long long &v) { vis.m->Uint64(v); }
void Reflect(JsonWriter &vis, double &v ) { vis.m->Double(v); }
void Reflect(JsonWriter &vis, const char *&v ) { vis.String(v); }
void Reflect(JsonWriter &vis, std::string &v ) { vis.String(v.c_str(), v.size()); }
void reflect(JsonWriter &vis, bool &v ) { vis.m->Bool(v); }
void reflect(JsonWriter &vis, unsigned char &v ) { vis.m->Int(v); }
void reflect(JsonWriter &vis, short &v ) { vis.m->Int(v); }
void reflect(JsonWriter &vis, unsigned short &v ) { vis.m->Int(v); }
void reflect(JsonWriter &vis, int &v ) { vis.m->Int(v); }
void reflect(JsonWriter &vis, unsigned &v ) { vis.m->Uint64(v); }
void reflect(JsonWriter &vis, long &v ) { vis.m->Int64(v); }
void reflect(JsonWriter &vis, unsigned long &v ) { vis.m->Uint64(v); }
void reflect(JsonWriter &vis, long long &v ) { vis.m->Int64(v); }
void reflect(JsonWriter &vis, unsigned long long &v) { vis.m->Uint64(v); }
void reflect(JsonWriter &vis, double &v ) { vis.m->Double(v); }
void reflect(JsonWriter &vis, const char *&v ) { vis.string(v); }
void reflect(JsonWriter &vis, std::string &v ) { vis.string(v.c_str(), v.size()); }
void Reflect(BinaryReader &vis, bool &v ) { v = vis.Get<bool>(); }
void Reflect(BinaryReader &vis, unsigned char &v ) { v = vis.Get<unsigned char>(); }
void Reflect(BinaryReader &vis, short &v ) { v = (short)vis.VarInt(); }
void Reflect(BinaryReader &vis, unsigned short &v ) { v = (unsigned short)vis.VarUInt(); }
void Reflect(BinaryReader &vis, int &v ) { v = (int)vis.VarInt(); }
void Reflect(BinaryReader &vis, unsigned &v ) { v = (unsigned)vis.VarUInt(); }
void Reflect(BinaryReader &vis, long &v ) { v = (long)vis.VarInt(); }
void Reflect(BinaryReader &vis, unsigned long &v ) { v = (unsigned long)vis.VarUInt(); }
void Reflect(BinaryReader &vis, long long &v ) { v = vis.VarInt(); }
void Reflect(BinaryReader &vis, unsigned long long &v) { v = vis.VarUInt(); }
void Reflect(BinaryReader &vis, double &v ) { v = vis.Get<double>(); }
void Reflect(BinaryReader &vis, const char *&v ) { v = Intern(vis.GetString()); }
void Reflect(BinaryReader &vis, std::string &v ) { v = vis.GetString(); }
void reflect(BinaryReader &vis, bool &v ) { v = vis.get<bool>(); }
void reflect(BinaryReader &vis, unsigned char &v ) { v = vis.get<unsigned char>(); }
void reflect(BinaryReader &vis, short &v ) { v = (short)vis.varInt(); }
void reflect(BinaryReader &vis, unsigned short &v ) { v = (unsigned short)vis.varUInt(); }
void reflect(BinaryReader &vis, int &v ) { v = (int)vis.varInt(); }
void reflect(BinaryReader &vis, unsigned &v ) { v = (unsigned)vis.varUInt(); }
void reflect(BinaryReader &vis, long &v ) { v = (long)vis.varInt(); }
void reflect(BinaryReader &vis, unsigned long &v ) { v = (unsigned long)vis.varUInt(); }
void reflect(BinaryReader &vis, long long &v ) { v = vis.varInt(); }
void reflect(BinaryReader &vis, unsigned long long &v) { v = vis.varUInt(); }
void reflect(BinaryReader &vis, double &v ) { v = vis.get<double>(); }
void reflect(BinaryReader &vis, const char *&v ) { v = intern(vis.getString()); }
void reflect(BinaryReader &vis, std::string &v ) { v = vis.getString(); }
void Reflect(BinaryWriter &vis, bool &v ) { vis.Pack(v); }
void Reflect(BinaryWriter &vis, unsigned char &v ) { vis.Pack(v); }
void Reflect(BinaryWriter &vis, short &v ) { vis.VarInt(v); }
void Reflect(BinaryWriter &vis, unsigned short &v ) { vis.VarUInt(v); }
void Reflect(BinaryWriter &vis, int &v ) { vis.VarInt(v); }
void Reflect(BinaryWriter &vis, unsigned &v ) { vis.VarUInt(v); }
void Reflect(BinaryWriter &vis, long &v ) { vis.VarInt(v); }
void Reflect(BinaryWriter &vis, unsigned long &v ) { vis.VarUInt(v); }
void Reflect(BinaryWriter &vis, long long &v ) { vis.VarInt(v); }
void Reflect(BinaryWriter &vis, unsigned long long &v) { vis.VarUInt(v); }
void Reflect(BinaryWriter &vis, double &v ) { vis.Pack(v); }
void Reflect(BinaryWriter &vis, const char *&v ) { vis.String(v); }
void Reflect(BinaryWriter &vis, std::string &v ) { vis.String(v.c_str(), v.size()); }
void reflect(BinaryWriter &vis, bool &v ) { vis.pack(v); }
void reflect(BinaryWriter &vis, unsigned char &v ) { vis.pack(v); }
void reflect(BinaryWriter &vis, short &v ) { vis.varInt(v); }
void reflect(BinaryWriter &vis, unsigned short &v ) { vis.varUInt(v); }
void reflect(BinaryWriter &vis, int &v ) { vis.varInt(v); }
void reflect(BinaryWriter &vis, unsigned &v ) { vis.varUInt(v); }
void reflect(BinaryWriter &vis, long &v ) { vis.varInt(v); }
void reflect(BinaryWriter &vis, unsigned long &v ) { vis.varUInt(v); }
void reflect(BinaryWriter &vis, long long &v ) { vis.varInt(v); }
void reflect(BinaryWriter &vis, unsigned long long &v) { vis.varUInt(v); }
void reflect(BinaryWriter &vis, double &v ) { vis.pack(v); }
void reflect(BinaryWriter &vis, const char *&v ) { vis.string(v); }
void reflect(BinaryWriter &vis, std::string &v ) { vis.string(v.c_str(), v.size()); }
// clang-format on
void Reflect(JsonWriter &vis, std::string_view &data) {
void reflect(JsonWriter &vis, std::string_view &data) {
if (data.empty())
vis.String("");
vis.string("");
else
vis.String(&data[0], (rapidjson::SizeType)data.size());
vis.string(&data[0], (rapidjson::SizeType)data.size());
}
void Reflect(JsonReader &vis, JsonNull &v) {}
void Reflect(JsonWriter &vis, JsonNull &v) { vis.m->Null(); }
void reflect(JsonReader &vis, JsonNull &v) {}
void reflect(JsonWriter &vis, JsonNull &v) { vis.m->Null(); }
template <typename V>
void Reflect(JsonReader &vis, std::unordered_map<Usr, V> &v) {
vis.IterArray([&]() {
void reflect(JsonReader &vis, std::unordered_map<Usr, V> &v) {
vis.iterArray([&]() {
V val;
Reflect(vis, val);
reflect(vis, val);
v[val.usr] = std::move(val);
});
}
template <typename V>
void Reflect(JsonWriter &vis, std::unordered_map<Usr, V> &v) {
void reflect(JsonWriter &vis, std::unordered_map<Usr, V> &v) {
// Determinism
std::vector<std::pair<uint64_t, V>> xs(v.begin(), v.end());
std::sort(xs.begin(), xs.end(),
[](const auto &a, const auto &b) { return a.first < b.first; });
vis.StartArray();
vis.startArray();
for (auto &it : xs)
Reflect(vis, it.second);
vis.EndArray();
reflect(vis, it.second);
vis.endArray();
}
template <typename V>
void Reflect(BinaryReader &vis, std::unordered_map<Usr, V> &v) {
for (auto n = vis.VarUInt(); n; n--) {
void reflect(BinaryReader &vis, std::unordered_map<Usr, V> &v) {
for (auto n = vis.varUInt(); n; n--) {
V val;
Reflect(vis, val);
reflect(vis, val);
v[val.usr] = std::move(val);
}
}
template <typename V>
void Reflect(BinaryWriter &vis, std::unordered_map<Usr, V> &v) {
vis.VarUInt(v.size());
void reflect(BinaryWriter &vis, std::unordered_map<Usr, V> &v) {
vis.varUInt(v.size());
for (auto &it : v)
Reflect(vis, it.second);
reflect(vis, it.second);
}
// Used by IndexFile::dependencies.
void Reflect(JsonReader &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
void reflect(JsonReader &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
std::string name;
for (auto it = vis.m->MemberBegin(); it != vis.m->MemberEnd(); ++it)
v[InternH(it->name.GetString())] = it->value.GetInt64();
v[internH(it->name.GetString())] = it->value.GetInt64();
}
void Reflect(JsonWriter &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
vis.StartObject();
void reflect(JsonWriter &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
vis.startObject();
for (auto &it : v) {
vis.m->Key(it.first.val().data()); // llvm 8 -> data()
vis.m->Int64(it.second);
}
vis.EndObject();
vis.endObject();
}
void Reflect(BinaryReader &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
void reflect(BinaryReader &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
std::string name;
for (auto n = vis.VarUInt(); n; n--) {
Reflect(vis, name);
Reflect(vis, v[InternH(name)]);
for (auto n = vis.varUInt(); n; n--) {
reflect(vis, name);
reflect(vis, v[internH(name)]);
}
}
void Reflect(BinaryWriter &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
void reflect(BinaryWriter &vis, DenseMap<CachedHashStringRef, int64_t> &v) {
std::string key;
vis.VarUInt(v.size());
vis.varUInt(v.size());
for (auto &it : v) {
key = it.first.val().str();
Reflect(vis, key);
Reflect(vis, it.second);
reflect(vis, key);
reflect(vis, it.second);
}
}
template <typename Vis> void Reflect(Vis &vis, IndexInclude &v) {
ReflectMemberStart(vis);
template <typename Vis> void reflect(Vis &vis, IndexInclude &v) {
reflectMemberStart(vis);
REFLECT_MEMBER(line);
REFLECT_MEMBER(resolved_path);
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
void Reflect(JsonWriter &vis, IndexInclude &v) {
ReflectMemberStart(vis);
void reflect(JsonWriter &vis, IndexInclude &v) {
reflectMemberStart(vis);
REFLECT_MEMBER(line);
if (gTestOutputMode) {
std::string basename = llvm::sys::path::filename(v.resolved_path);
@ -224,73 +224,73 @@ void Reflect(JsonWriter &vis, IndexInclude &v) {
} else {
REFLECT_MEMBER(resolved_path);
}
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
template <typename Def>
void ReflectHoverAndComments(JsonReader &vis, Def &def) {
ReflectMember(vis, "hover", def.hover);
ReflectMember(vis, "comments", def.comments);
void reflectHoverAndComments(JsonReader &vis, Def &def) {
reflectMember(vis, "hover", def.hover);
reflectMember(vis, "comments", def.comments);
}
template <typename Def>
void ReflectHoverAndComments(JsonWriter &vis, Def &def) {
void reflectHoverAndComments(JsonWriter &vis, Def &def) {
// Don't emit empty hover and comments in JSON test mode.
if (!gTestOutputMode || def.hover[0])
ReflectMember(vis, "hover", def.hover);
reflectMember(vis, "hover", def.hover);
if (!gTestOutputMode || def.comments[0])
ReflectMember(vis, "comments", def.comments);
reflectMember(vis, "comments", def.comments);
}
template <typename Def>
void ReflectHoverAndComments(BinaryReader &vis, Def &def) {
Reflect(vis, def.hover);
Reflect(vis, def.comments);
void reflectHoverAndComments(BinaryReader &vis, Def &def) {
reflect(vis, def.hover);
reflect(vis, def.comments);
}
template <typename Def>
void ReflectHoverAndComments(BinaryWriter &vis, Def &def) {
Reflect(vis, def.hover);
Reflect(vis, def.comments);
void reflectHoverAndComments(BinaryWriter &vis, Def &def) {
reflect(vis, def.hover);
reflect(vis, def.comments);
}
template <typename Def> void ReflectShortName(JsonReader &vis, Def &def) {
template <typename Def> void reflectShortName(JsonReader &vis, Def &def) {
if (gTestOutputMode) {
std::string short_name;
ReflectMember(vis, "short_name", short_name);
reflectMember(vis, "short_name", short_name);
def.short_name_offset =
std::string_view(def.detailed_name).find(short_name);
assert(def.short_name_offset != std::string::npos);
def.short_name_size = short_name.size();
} else {
ReflectMember(vis, "short_name_offset", def.short_name_offset);
ReflectMember(vis, "short_name_size", def.short_name_size);
reflectMember(vis, "short_name_offset", def.short_name_offset);
reflectMember(vis, "short_name_size", def.short_name_size);
}
}
template <typename Def> void ReflectShortName(JsonWriter &vis, Def &def) {
template <typename Def> void reflectShortName(JsonWriter &vis, Def &def) {
if (gTestOutputMode) {
std::string_view short_name(def.detailed_name + def.short_name_offset,
def.short_name_size);
ReflectMember(vis, "short_name", short_name);
reflectMember(vis, "short_name", short_name);
} else {
ReflectMember(vis, "short_name_offset", def.short_name_offset);
ReflectMember(vis, "short_name_size", def.short_name_size);
reflectMember(vis, "short_name_offset", def.short_name_offset);
reflectMember(vis, "short_name_size", def.short_name_size);
}
}
template <typename Def> void ReflectShortName(BinaryReader &vis, Def &def) {
Reflect(vis, def.short_name_offset);
Reflect(vis, def.short_name_size);
template <typename Def> void reflectShortName(BinaryReader &vis, Def &def) {
reflect(vis, def.short_name_offset);
reflect(vis, def.short_name_size);
}
template <typename Def> void ReflectShortName(BinaryWriter &vis, Def &def) {
Reflect(vis, def.short_name_offset);
Reflect(vis, def.short_name_size);
template <typename Def> void reflectShortName(BinaryWriter &vis, Def &def) {
reflect(vis, def.short_name_offset);
reflect(vis, def.short_name_size);
}
template <typename TVisitor> void Reflect1(TVisitor &vis, IndexFunc &v) {
ReflectMemberStart(vis);
template <typename TVisitor> void reflect1(TVisitor &vis, IndexFunc &v) {
reflectMemberStart(vis);
REFLECT_MEMBER2("usr", v.usr);
REFLECT_MEMBER2("detailed_name", v.def.detailed_name);
REFLECT_MEMBER2("qual_name_offset", v.def.qual_name_offset);
ReflectShortName(vis, v.def);
reflectShortName(vis, v.def);
REFLECT_MEMBER2("spell", v.def.spell);
ReflectHoverAndComments(vis, v.def);
reflectHoverAndComments(vis, v.def);
REFLECT_MEMBER2("bases", v.def.bases);
REFLECT_MEMBER2("vars", v.def.vars);
REFLECT_MEMBER2("callees", v.def.callees);
@ -301,20 +301,20 @@ template <typename TVisitor> void Reflect1(TVisitor &vis, IndexFunc &v) {
REFLECT_MEMBER2("declarations", v.declarations);
REFLECT_MEMBER2("derived", v.derived);
REFLECT_MEMBER2("uses", v.uses);
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
void Reflect(JsonReader &vis, IndexFunc &v) { Reflect1(vis, v); }
void Reflect(JsonWriter &vis, IndexFunc &v) { Reflect1(vis, v); }
void Reflect(BinaryReader &vis, IndexFunc &v) { Reflect1(vis, v); }
void Reflect(BinaryWriter &vis, IndexFunc &v) { Reflect1(vis, v); }
void reflect(JsonReader &vis, IndexFunc &v) { reflect1(vis, v); }
void reflect(JsonWriter &vis, IndexFunc &v) { reflect1(vis, v); }
void reflect(BinaryReader &vis, IndexFunc &v) { reflect1(vis, v); }
void reflect(BinaryWriter &vis, IndexFunc &v) { reflect1(vis, v); }
template <typename TVisitor> void Reflect1(TVisitor &vis, IndexType &v) {
ReflectMemberStart(vis);
template <typename Vis> void reflect1(Vis &vis, IndexType &v) {
reflectMemberStart(vis);
REFLECT_MEMBER2("usr", v.usr);
REFLECT_MEMBER2("detailed_name", v.def.detailed_name);
REFLECT_MEMBER2("qual_name_offset", v.def.qual_name_offset);
ReflectShortName(vis, v.def);
ReflectHoverAndComments(vis, v.def);
reflectShortName(vis, v.def);
reflectHoverAndComments(vis, v.def);
REFLECT_MEMBER2("spell", v.def.spell);
REFLECT_MEMBER2("bases", v.def.bases);
REFLECT_MEMBER2("funcs", v.def.funcs);
@ -328,20 +328,20 @@ template <typename TVisitor> void Reflect1(TVisitor &vis, IndexType &v) {
REFLECT_MEMBER2("derived", v.derived);
REFLECT_MEMBER2("instances", v.instances);
REFLECT_MEMBER2("uses", v.uses);
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
void Reflect(JsonReader &vis, IndexType &v) { Reflect1(vis, v); }
void Reflect(JsonWriter &vis, IndexType &v) { Reflect1(vis, v); }
void Reflect(BinaryReader &vis, IndexType &v) { Reflect1(vis, v); }
void Reflect(BinaryWriter &vis, IndexType &v) { Reflect1(vis, v); }
void reflect(JsonReader &vis, IndexType &v) { reflect1(vis, v); }
void reflect(JsonWriter &vis, IndexType &v) { reflect1(vis, v); }
void reflect(BinaryReader &vis, IndexType &v) { reflect1(vis, v); }
void reflect(BinaryWriter &vis, IndexType &v) { reflect1(vis, v); }
template <typename TVisitor> void Reflect1(TVisitor &vis, IndexVar &v) {
ReflectMemberStart(vis);
template <typename TVisitor> void reflect1(TVisitor &vis, IndexVar &v) {
reflectMemberStart(vis);
REFLECT_MEMBER2("usr", v.usr);
REFLECT_MEMBER2("detailed_name", v.def.detailed_name);
REFLECT_MEMBER2("qual_name_offset", v.def.qual_name_offset);
ReflectShortName(vis, v.def);
ReflectHoverAndComments(vis, v.def);
reflectShortName(vis, v.def);
reflectHoverAndComments(vis, v.def);
REFLECT_MEMBER2("spell", v.def.spell);
REFLECT_MEMBER2("type", v.def.type);
REFLECT_MEMBER2("kind", v.def.kind);
@ -350,16 +350,16 @@ template <typename TVisitor> void Reflect1(TVisitor &vis, IndexVar &v) {
REFLECT_MEMBER2("declarations", v.declarations);
REFLECT_MEMBER2("uses", v.uses);
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
void Reflect(JsonReader &vis, IndexVar &v) { Reflect1(vis, v); }
void Reflect(JsonWriter &vis, IndexVar &v) { Reflect1(vis, v); }
void Reflect(BinaryReader &vis, IndexVar &v) { Reflect1(vis, v); }
void Reflect(BinaryWriter &vis, IndexVar &v) { Reflect1(vis, v); }
void reflect(JsonReader &vis, IndexVar &v) { reflect1(vis, v); }
void reflect(JsonWriter &vis, IndexVar &v) { reflect1(vis, v); }
void reflect(BinaryReader &vis, IndexVar &v) { reflect1(vis, v); }
void reflect(BinaryWriter &vis, IndexVar &v) { reflect1(vis, v); }
// IndexFile
template <typename TVisitor> void Reflect1(TVisitor &vis, IndexFile &v) {
ReflectMemberStart(vis);
template <typename TVisitor> void reflect1(TVisitor &vis, IndexFile &v) {
reflectMemberStart(vis);
if (!gTestOutputMode) {
REFLECT_MEMBER(mtime);
REFLECT_MEMBER(language);
@ -374,67 +374,65 @@ template <typename TVisitor> void Reflect1(TVisitor &vis, IndexFile &v) {
REFLECT_MEMBER(usr2func);
REFLECT_MEMBER(usr2type);
REFLECT_MEMBER(usr2var);
ReflectMemberEnd(vis);
reflectMemberEnd(vis);
}
void ReflectFile(JsonReader &vis, IndexFile &v) { Reflect1(vis, v); }
void ReflectFile(JsonWriter &vis, IndexFile &v) { Reflect1(vis, v); }
void ReflectFile(BinaryReader &vis, IndexFile &v) { Reflect1(vis, v); }
void ReflectFile(BinaryWriter &vis, IndexFile &v) { Reflect1(vis, v); }
void reflectFile(JsonReader &vis, IndexFile &v) { reflect1(vis, v); }
void reflectFile(JsonWriter &vis, IndexFile &v) { reflect1(vis, v); }
void reflectFile(BinaryReader &vis, IndexFile &v) { reflect1(vis, v); }
void reflectFile(BinaryWriter &vis, IndexFile &v) { reflect1(vis, v); }
void Reflect(JsonReader &vis, SerializeFormat &v) {
v = vis.GetString()[0] == 'j' ? SerializeFormat::Json
void reflect(JsonReader &vis, SerializeFormat &v) {
v = vis.getString()[0] == 'j' ? SerializeFormat::Json
: SerializeFormat::Binary;
}
void Reflect(JsonWriter &vis, SerializeFormat &v) {
void reflect(JsonWriter &vis, SerializeFormat &v) {
switch (v) {
case SerializeFormat::Binary:
vis.String("binary");
vis.string("binary");
break;
case SerializeFormat::Json:
vis.String("json");
vis.string("json");
break;
}
}
void ReflectMemberStart(JsonReader &vis) {
void reflectMemberStart(JsonReader &vis) {
if (!vis.m->IsObject())
throw std::invalid_argument("object");
}
static BumpPtrAllocator Alloc;
static DenseSet<CachedHashStringRef> Strings;
static std::mutex AllocMutex;
static BumpPtrAllocator alloc;
static DenseSet<CachedHashStringRef> strings;
static std::mutex allocMutex;
CachedHashStringRef InternH(StringRef S) {
if (S.empty())
S = "";
CachedHashString HS(S);
std::lock_guard lock(AllocMutex);
auto R = Strings.insert(HS);
if (R.second) {
char *P = Alloc.Allocate<char>(S.size() + 1);
memcpy(P, S.data(), S.size());
P[S.size()] = '\0';
*R.first = CachedHashStringRef(StringRef(P, S.size()), HS.hash());
CachedHashStringRef internH(StringRef s) {
if (s.empty())
s = "";
CachedHashString hs(s);
std::lock_guard lock(allocMutex);
auto r = strings.insert(hs);
if (r.second) {
char *p = alloc.Allocate<char>(s.size() + 1);
memcpy(p, s.data(), s.size());
p[s.size()] = '\0';
*r.first = CachedHashStringRef(StringRef(p, s.size()), hs.hash());
}
return *R.first;
return *r.first;
}
const char *Intern(StringRef S) {
return InternH(S).val().data();
}
const char *intern(StringRef s) { return internH(s).val().data(); }
std::string Serialize(SerializeFormat format, IndexFile &file) {
std::string serialize(SerializeFormat format, IndexFile &file) {
switch (format) {
case SerializeFormat::Binary: {
BinaryWriter writer;
int major = IndexFile::kMajorVersion;
int minor = IndexFile::kMinorVersion;
Reflect(writer, major);
Reflect(writer, minor);
ReflectFile(writer, file);
return writer.Take();
reflect(writer, major);
reflect(writer, minor);
reflectFile(writer, file);
return writer.take();
}
case SerializeFormat::Json: {
rapidjson::StringBuffer output;
@ -449,7 +447,7 @@ std::string Serialize(SerializeFormat format, IndexFile &file) {
output.Put(c);
output.Put('\n');
}
ReflectFile(json_writer, file);
reflectFile(json_writer, file);
return output.GetString();
}
}
@ -457,7 +455,7 @@ std::string Serialize(SerializeFormat format, IndexFile &file) {
}
std::unique_ptr<IndexFile>
Deserialize(SerializeFormat format, const std::string &path,
deserialize(SerializeFormat format, const std::string &path,
const std::string &serialized_index_content,
const std::string &file_content,
std::optional<int> expected_version) {
@ -472,13 +470,13 @@ Deserialize(SerializeFormat format, const std::string &path,
if (serialized_index_content.size() < 8)
throw std::invalid_argument("Invalid");
BinaryReader reader(serialized_index_content);
Reflect(reader, major);
Reflect(reader, minor);
reflect(reader, major);
reflect(reader, minor);
if (major != IndexFile::kMajorVersion ||
minor != IndexFile::kMinorVersion)
throw std::invalid_argument("Invalid version");
file = std::make_unique<IndexFile>(path, file_content, false);
ReflectFile(reader, *file);
reflectFile(reader, *file);
} catch (std::invalid_argument &e) {
LOG_S(INFO) << "failed to deserialize '" << path << "': " << e.what();
return nullptr;
@ -503,10 +501,10 @@ Deserialize(SerializeFormat format, const std::string &path,
file = std::make_unique<IndexFile>(path, file_content, false);
JsonReader json_reader{&reader};
try {
ReflectFile(json_reader, *file);
reflectFile(json_reader, *file);
} catch (std::invalid_argument &e) {
LOG_S(INFO) << "'" << path << "': failed to deserialize "
<< json_reader.GetPath() << "." << e.what();
<< json_reader.getPath() << "." << e.what();
return nullptr;
}
break;
@ -516,26 +514,26 @@ Deserialize(SerializeFormat format, const std::string &path,
// Restore non-serialized state.
file->path = path;
if (g_config->clang.pathMappings.size()) {
DoPathMapping(file->import_file);
doPathMapping(file->import_file);
std::vector<const char *> args;
for (const char *arg : file->args) {
std::string s(arg);
DoPathMapping(s);
args.push_back(Intern(s));
doPathMapping(s);
args.push_back(intern(s));
}
file->args = std::move(args);
for (auto &[_, path] : file->lid2path)
DoPathMapping(path);
doPathMapping(path);
for (auto &include : file->includes) {
std::string p(include.resolved_path);
DoPathMapping(p);
include.resolved_path = Intern(p);
doPathMapping(p);
include.resolved_path = intern(p);
}
decltype(file->dependencies) dependencies;
for (auto &it : file->dependencies) {
std::string path = it.first.val().str();
DoPathMapping(path);
dependencies[InternH(path)] = it.second;
doPathMapping(path);
dependencies[internH(path)] = it.second;
}
file->dependencies = std::move(dependencies);
}

View File

@ -22,7 +22,7 @@
namespace llvm {
class CachedHashStringRef;
class StringRef;
}
} // namespace llvm
namespace ccls {
enum class SerializeFormat { Binary, Json };
@ -34,13 +34,13 @@ struct JsonReader {
std::vector<const char *> path_;
JsonReader(rapidjson::Value *m) : m(m) {}
void StartObject() {}
void EndObject() {}
void IterArray(std::function<void()> fn);
void Member(const char *name, std::function<void()> fn);
bool IsNull();
std::string GetString();
std::string GetPath() const;
void startObject() {}
void endObject() {}
void iterArray(std::function<void()> fn);
void member(const char *name, std::function<void()> fn);
bool isNull();
std::string getString();
std::string getPath() const;
};
struct JsonWriter {
@ -51,42 +51,42 @@ struct JsonWriter {
W *m;
JsonWriter(W *m) : m(m) {}
void StartArray();
void EndArray();
void StartObject();
void EndObject();
void Key(const char *name);
void Null();
void Int(int v);
void String(const char *s);
void String(const char *s, size_t len);
void startArray();
void endArray();
void startObject();
void endObject();
void key(const char *name);
void null_();
void int_(int v);
void string(const char *s);
void string(const char *s, size_t len);
};
struct BinaryReader {
const char *p_;
BinaryReader(std::string_view buf) : p_(buf.data()) {}
template <typename T> T Get() {
template <typename T> T get() {
T ret;
memcpy(&ret, p_, sizeof(T));
p_ += sizeof(T);
return ret;
}
uint64_t VarUInt() {
uint64_t varUInt() {
auto x = *reinterpret_cast<const uint8_t *>(p_++);
if (x < 253)
return x;
if (x == 253)
return Get<uint16_t>();
return get<uint16_t>();
if (x == 254)
return Get<uint32_t>();
return Get<uint64_t>();
return get<uint32_t>();
return get<uint64_t>();
}
int64_t VarInt() {
uint64_t x = VarUInt();
int64_t varInt() {
uint64_t x = varUInt();
return int64_t(x >> 1 ^ -(x & 1));
}
const char *GetString() {
const char *getString() {
const char *ret = p_;
while (*p_)
p_++;
@ -98,31 +98,31 @@ struct BinaryReader {
struct BinaryWriter {
std::string buf_;
template <typename T> void Pack(T x) {
template <typename T> void pack(T x) {
auto i = buf_.size();
buf_.resize(i + sizeof(x));
memcpy(buf_.data() + i, &x, sizeof(x));
}
void VarUInt(uint64_t n) {
void varUInt(uint64_t n) {
if (n < 253)
Pack<uint8_t>(n);
pack<uint8_t>(n);
else if (n < 65536) {
Pack<uint8_t>(253);
Pack<uint16_t>(n);
pack<uint8_t>(253);
pack<uint16_t>(n);
} else if (n < 4294967296) {
Pack<uint8_t>(254);
Pack<uint32_t>(n);
pack<uint8_t>(254);
pack<uint32_t>(n);
} else {
Pack<uint8_t>(255);
Pack<uint64_t>(n);
pack<uint8_t>(255);
pack<uint64_t>(n);
}
}
void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); }
std::string Take() { return std::move(buf_); }
void varInt(int64_t n) { varUInt(uint64_t(n) << 1 ^ n >> 63); }
std::string take() { return std::move(buf_); }
void String(const char *x) { String(x, strlen(x)); }
void String(const char *x, size_t len) {
void string(const char *x) { string(x, strlen(x)); }
void string(const char *x, size_t len) {
auto i = buf_.size();
buf_.resize(i + len + 1);
memcpy(buf_.data() + i, x, len);
@ -131,270 +131,274 @@ struct BinaryWriter {
struct IndexFile;
#define REFLECT_MEMBER(name) ReflectMember(vis, #name, v.name)
#define REFLECT_MEMBER2(name, v) ReflectMember(vis, name, v)
#define REFLECT_MEMBER(name) reflectMember(vis, #name, v.name)
#define REFLECT_MEMBER2(name, v) reflectMember(vis, name, v)
#define REFLECT_UNDERLYING(T) \
LLVM_ATTRIBUTE_UNUSED inline void Reflect(JsonReader &vis, T &v) { \
LLVM_ATTRIBUTE_UNUSED inline void reflect(JsonReader &vis, T &v) { \
std::underlying_type_t<T> v0; \
::ccls::Reflect(vis, v0); \
::ccls::reflect(vis, v0); \
v = static_cast<T>(v0); \
} \
LLVM_ATTRIBUTE_UNUSED inline void Reflect(JsonWriter &vis, T &v) { \
LLVM_ATTRIBUTE_UNUSED inline void reflect(JsonWriter &vis, T &v) { \
auto v0 = static_cast<std::underlying_type_t<T>>(v); \
::ccls::Reflect(vis, v0); \
::ccls::reflect(vis, v0); \
}
#define REFLECT_UNDERLYING_B(T) \
REFLECT_UNDERLYING(T) \
LLVM_ATTRIBUTE_UNUSED inline void Reflect(BinaryReader &vis, T &v) { \
LLVM_ATTRIBUTE_UNUSED inline void reflect(BinaryReader &vis, T &v) { \
std::underlying_type_t<T> v0; \
::ccls::Reflect(vis, v0); \
::ccls::reflect(vis, v0); \
v = static_cast<T>(v0); \
} \
LLVM_ATTRIBUTE_UNUSED inline void Reflect(BinaryWriter &vis, T &v) { \
LLVM_ATTRIBUTE_UNUSED inline void reflect(BinaryWriter &vis, T &v) { \
auto v0 = static_cast<std::underlying_type_t<T>>(v); \
::ccls::Reflect(vis, v0); \
::ccls::reflect(vis, v0); \
}
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
#define REFLECT_STRUCT(type, ...) \
template <typename Vis> void Reflect(Vis &vis, type &v) { \
ReflectMemberStart(vis); \
template <typename Vis> void reflect(Vis &vis, type &v) { \
reflectMemberStart(vis); \
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \
ReflectMemberEnd(vis); \
reflectMemberEnd(vis); \
}
#define _MAPPABLE_REFLECT_ARRAY(name) Reflect(vis, v.name);
#define _MAPPABLE_REFLECT_ARRAY(name) reflect(vis, v.name);
void Reflect(JsonReader &vis, bool &v);
void Reflect(JsonReader &vis, unsigned char &v);
void Reflect(JsonReader &vis, short &v);
void Reflect(JsonReader &vis, unsigned short &v);
void Reflect(JsonReader &vis, int &v);
void Reflect(JsonReader &vis, unsigned &v);
void Reflect(JsonReader &vis, long &v);
void Reflect(JsonReader &vis, unsigned long &v);
void Reflect(JsonReader &vis, long long &v);
void Reflect(JsonReader &vis, unsigned long long &v);
void Reflect(JsonReader &vis, double &v);
void Reflect(JsonReader &vis, const char *&v);
void Reflect(JsonReader &vis, std::string &v);
void reflect(JsonReader &vis, bool &v);
void reflect(JsonReader &vis, unsigned char &v);
void reflect(JsonReader &vis, short &v);
void reflect(JsonReader &vis, unsigned short &v);
void reflect(JsonReader &vis, int &v);
void reflect(JsonReader &vis, unsigned &v);
void reflect(JsonReader &vis, long &v);
void reflect(JsonReader &vis, unsigned long &v);
void reflect(JsonReader &vis, long long &v);
void reflect(JsonReader &vis, unsigned long long &v);
void reflect(JsonReader &vis, double &v);
void reflect(JsonReader &vis, const char *&v);
void reflect(JsonReader &vis, std::string &v);
void Reflect(JsonWriter &vis, bool &v);
void Reflect(JsonWriter &vis, unsigned char &v);
void Reflect(JsonWriter &vis, short &v);
void Reflect(JsonWriter &vis, unsigned short &v);
void Reflect(JsonWriter &vis, int &v);
void Reflect(JsonWriter &vis, unsigned &v);
void Reflect(JsonWriter &vis, long &v);
void Reflect(JsonWriter &vis, unsigned long &v);
void Reflect(JsonWriter &vis, long long &v);
void Reflect(JsonWriter &vis, unsigned long long &v);
void Reflect(JsonWriter &vis, double &v);
void Reflect(JsonWriter &vis, const char *&v);
void Reflect(JsonWriter &vis, std::string &v);
void reflect(JsonWriter &vis, bool &v);
void reflect(JsonWriter &vis, unsigned char &v);
void reflect(JsonWriter &vis, short &v);
void reflect(JsonWriter &vis, unsigned short &v);
void reflect(JsonWriter &vis, int &v);
void reflect(JsonWriter &vis, unsigned &v);
void reflect(JsonWriter &vis, long &v);
void reflect(JsonWriter &vis, unsigned long &v);
void reflect(JsonWriter &vis, long long &v);
void reflect(JsonWriter &vis, unsigned long long &v);
void reflect(JsonWriter &vis, double &v);
void reflect(JsonWriter &vis, const char *&v);
void reflect(JsonWriter &vis, std::string &v);
void Reflect(BinaryReader &vis, bool &v);
void Reflect(BinaryReader &vis, unsigned char &v);
void Reflect(BinaryReader &vis, short &v);
void Reflect(BinaryReader &vis, unsigned short &v);
void Reflect(BinaryReader &vis, int &v);
void Reflect(BinaryReader &vis, unsigned &v);
void Reflect(BinaryReader &vis, long &v);
void Reflect(BinaryReader &vis, unsigned long &v);
void Reflect(BinaryReader &vis, long long &v);
void Reflect(BinaryReader &vis, unsigned long long &v);
void Reflect(BinaryReader &vis, double &v);
void Reflect(BinaryReader &vis, const char *&v);
void Reflect(BinaryReader &vis, std::string &v);
void reflect(BinaryReader &vis, bool &v);
void reflect(BinaryReader &vis, unsigned char &v);
void reflect(BinaryReader &vis, short &v);
void reflect(BinaryReader &vis, unsigned short &v);
void reflect(BinaryReader &vis, int &v);
void reflect(BinaryReader &vis, unsigned &v);
void reflect(BinaryReader &vis, long &v);
void reflect(BinaryReader &vis, unsigned long &v);
void reflect(BinaryReader &vis, long long &v);
void reflect(BinaryReader &vis, unsigned long long &v);
void reflect(BinaryReader &vis, double &v);
void reflect(BinaryReader &vis, const char *&v);
void reflect(BinaryReader &vis, std::string &v);
void Reflect(BinaryWriter &vis, bool &v);
void Reflect(BinaryWriter &vis, unsigned char &v);
void Reflect(BinaryWriter &vis, short &v);
void Reflect(BinaryWriter &vis, unsigned short &v);
void Reflect(BinaryWriter &vis, int &v);
void Reflect(BinaryWriter &vis, unsigned &v);
void Reflect(BinaryWriter &vis, long &v);
void Reflect(BinaryWriter &vis, unsigned long &v);
void Reflect(BinaryWriter &vis, long long &v);
void Reflect(BinaryWriter &vis, unsigned long long &v);
void Reflect(BinaryWriter &vis, double &v);
void Reflect(BinaryWriter &vis, const char *&v);
void Reflect(BinaryWriter &vis, std::string &v);
void reflect(BinaryWriter &vis, bool &v);
void reflect(BinaryWriter &vis, unsigned char &v);
void reflect(BinaryWriter &vis, short &v);
void reflect(BinaryWriter &vis, unsigned short &v);
void reflect(BinaryWriter &vis, int &v);
void reflect(BinaryWriter &vis, unsigned &v);
void reflect(BinaryWriter &vis, long &v);
void reflect(BinaryWriter &vis, unsigned long &v);
void reflect(BinaryWriter &vis, long long &v);
void reflect(BinaryWriter &vis, unsigned long long &v);
void reflect(BinaryWriter &vis, double &v);
void reflect(BinaryWriter &vis, const char *&v);
void reflect(BinaryWriter &vis, std::string &v);
void Reflect(JsonReader &vis, JsonNull &v);
void Reflect(JsonWriter &vis, JsonNull &v);
void reflect(JsonReader &vis, JsonNull &v);
void reflect(JsonWriter &vis, JsonNull &v);
void Reflect(JsonReader &vis, SerializeFormat &v);
void Reflect(JsonWriter &vis, SerializeFormat &v);
void reflect(JsonReader &vis, SerializeFormat &v);
void reflect(JsonWriter &vis, SerializeFormat &v);
void Reflect(JsonWriter &vis, std::string_view &v);
void reflect(JsonWriter &vis, std::string_view &v);
//// Type constructors
// ReflectMember std::optional<T> is used to represent TypeScript optional
// properties (in `key: value` context). Reflect std::optional<T> is used for a
// reflectMember std::optional<T> is used to represent TypeScript optional
// properties (in `key: value` context). reflect std::optional<T> is used for a
// different purpose, whether an object is nullable (possibly in `value`
// context).
template <typename T> void Reflect(JsonReader &vis, std::optional<T> &v) {
if (!vis.IsNull()) {
template <typename T> void reflect(JsonReader &vis, std::optional<T> &v) {
if (!vis.isNull()) {
v.emplace();
Reflect(vis, *v);
reflect(vis, *v);
}
}
template <typename T> void Reflect(JsonWriter &vis, std::optional<T> &v) {
template <typename T> void reflect(JsonWriter &vis, std::optional<T> &v) {
if (v)
Reflect(vis, *v);
reflect(vis, *v);
else
vis.Null();
vis.null_();
}
template <typename T> void Reflect(BinaryReader &vis, std::optional<T> &v) {
template <typename T> void reflect(BinaryReader &vis, std::optional<T> &v) {
if (*vis.p_++) {
v.emplace();
Reflect(vis, *v);
reflect(vis, *v);
}
}
template <typename T> void Reflect(BinaryWriter &vis, std::optional<T> &v) {
template <typename T> void reflect(BinaryWriter &vis, std::optional<T> &v) {
if (v) {
vis.Pack<unsigned char>(1);
Reflect(vis, *v);
vis.pack<unsigned char>(1);
reflect(vis, *v);
} else {
vis.Pack<unsigned char>(0);
vis.pack<unsigned char>(0);
}
}
// The same as std::optional
template <typename T> void Reflect(JsonReader &vis, Maybe<T> &v) {
if (!vis.IsNull())
Reflect(vis, *v);
template <typename T> void reflect(JsonReader &vis, Maybe<T> &v) {
if (!vis.isNull())
reflect(vis, *v);
}
template <typename T> void Reflect(JsonWriter &vis, Maybe<T> &v) {
template <typename T> void reflect(JsonWriter &vis, Maybe<T> &v) {
if (v)
Reflect(vis, *v);
reflect(vis, *v);
else
vis.Null();
vis.null_();
}
template <typename T> void Reflect(BinaryReader &vis, Maybe<T> &v) {
template <typename T> void reflect(BinaryReader &vis, Maybe<T> &v) {
if (*vis.p_++)
Reflect(vis, *v);
reflect(vis, *v);
}
template <typename T> void Reflect(BinaryWriter &vis, Maybe<T> &v) {
template <typename T> void reflect(BinaryWriter &vis, Maybe<T> &v) {
if (v) {
vis.Pack<unsigned char>(1);
Reflect(vis, *v);
vis.pack<unsigned char>(1);
reflect(vis, *v);
} else {
vis.Pack<unsigned char>(0);
vis.pack<unsigned char>(0);
}
}
template <typename T>
void ReflectMember(JsonWriter &vis, const char *name, std::optional<T> &v) {
void reflectMember(JsonWriter &vis, const char *name, std::optional<T> &v) {
// For TypeScript std::optional property key?: value in the spec,
// We omit both key and value if value is std::nullopt (null) for JsonWriter
// to reduce output. But keep it for other serialization formats.
if (v) {
vis.Key(name);
Reflect(vis, *v);
vis.key(name);
reflect(vis, *v);
}
}
template <typename T>
void ReflectMember(BinaryWriter &vis, const char *, std::optional<T> &v) {
Reflect(vis, v);
void reflectMember(BinaryWriter &vis, const char *, std::optional<T> &v) {
reflect(vis, v);
}
// The same as std::optional
template <typename T>
void ReflectMember(JsonWriter &vis, const char *name, Maybe<T> &v) {
if (v.Valid()) {
vis.Key(name);
Reflect(vis, v);
void reflectMember(JsonWriter &vis, const char *name, Maybe<T> &v) {
if (v.valid()) {
vis.key(name);
reflect(vis, v);
}
}
template <typename T>
void ReflectMember(BinaryWriter &vis, const char *, Maybe<T> &v) {
Reflect(vis, v);
void reflectMember(BinaryWriter &vis, const char *, Maybe<T> &v) {
reflect(vis, v);
}
template <typename L, typename R>
void Reflect(JsonReader &vis, std::pair<L, R> &v) {
vis.Member("L", [&]() { Reflect(vis, v.first); });
vis.Member("R", [&]() { Reflect(vis, v.second); });
void reflect(JsonReader &vis, std::pair<L, R> &v) {
vis.member("L", [&]() { reflect(vis, v.first); });
vis.member("R", [&]() { reflect(vis, v.second); });
}
template <typename L, typename R>
void Reflect(JsonWriter &vis, std::pair<L, R> &v) {
vis.StartObject();
ReflectMember(vis, "L", v.first);
ReflectMember(vis, "R", v.second);
vis.EndObject();
void reflect(JsonWriter &vis, std::pair<L, R> &v) {
vis.startObject();
reflectMember(vis, "L", v.first);
reflectMember(vis, "R", v.second);
vis.endObject();
}
template <typename L, typename R>
void Reflect(BinaryReader &vis, std::pair<L, R> &v) {
Reflect(vis, v.first);
Reflect(vis, v.second);
void reflect(BinaryReader &vis, std::pair<L, R> &v) {
reflect(vis, v.first);
reflect(vis, v.second);
}
template <typename L, typename R>
void Reflect(BinaryWriter &vis, std::pair<L, R> &v) {
Reflect(vis, v.first);
Reflect(vis, v.second);
void reflect(BinaryWriter &vis, std::pair<L, R> &v) {
reflect(vis, v.first);
reflect(vis, v.second);
}
// std::vector
template <typename T> void Reflect(JsonReader &vis, std::vector<T> &v) {
vis.IterArray([&]() {
template <typename T> void reflect(JsonReader &vis, std::vector<T> &v) {
vis.iterArray([&]() {
v.emplace_back();
Reflect(vis, v.back());
reflect(vis, v.back());
});
}
template <typename T> void Reflect(JsonWriter &vis, std::vector<T> &v) {
vis.StartArray();
template <typename T> void reflect(JsonWriter &vis, std::vector<T> &v) {
vis.startArray();
for (auto &it : v)
Reflect(vis, it);
vis.EndArray();
reflect(vis, it);
vis.endArray();
}
template <typename T> void Reflect(BinaryReader &vis, std::vector<T> &v) {
for (auto n = vis.VarUInt(); n; n--) {
template <typename T> void reflect(BinaryReader &vis, std::vector<T> &v) {
for (auto n = vis.varUInt(); n; n--) {
v.emplace_back();
Reflect(vis, v.back());
reflect(vis, v.back());
}
}
template <typename T> void Reflect(BinaryWriter &vis, std::vector<T> &v) {
vis.VarUInt(v.size());
template <typename T> void reflect(BinaryWriter &vis, std::vector<T> &v) {
vis.varUInt(v.size());
for (auto &it : v)
Reflect(vis, it);
reflect(vis, it);
}
// ReflectMember
// reflectMember
void ReflectMemberStart(JsonReader &);
template <typename T> void ReflectMemberStart(T &) {}
inline void ReflectMemberStart(JsonWriter &vis) { vis.StartObject(); }
void reflectMemberStart(JsonReader &);
template <typename T> void reflectMemberStart(T &) {}
inline void reflectMemberStart(JsonWriter &vis) { vis.startObject(); }
template <typename T> void ReflectMemberEnd(T &) {}
inline void ReflectMemberEnd(JsonWriter &vis) { vis.EndObject(); }
template <typename T> void reflectMemberEnd(T &) {}
inline void reflectMemberEnd(JsonWriter &vis) { vis.endObject(); }
template <typename T> void ReflectMember(JsonReader &vis, const char *name, T &v) {
vis.Member(name, [&]() { Reflect(vis, v); });
template <typename T>
void reflectMember(JsonReader &vis, const char *name, T &v) {
vis.member(name, [&]() { reflect(vis, v); });
}
template <typename T> void ReflectMember(JsonWriter &vis, const char *name, T &v) {
vis.Key(name);
Reflect(vis, v);
template <typename T>
void reflectMember(JsonWriter &vis, const char *name, T &v) {
vis.key(name);
reflect(vis, v);
}
template <typename T> void ReflectMember(BinaryReader &vis, const char *, T &v) {
Reflect(vis, v);
template <typename T>
void reflectMember(BinaryReader &vis, const char *, T &v) {
reflect(vis, v);
}
template <typename T> void ReflectMember(BinaryWriter &vis, const char *, T &v) {
Reflect(vis, v);
template <typename T>
void reflectMember(BinaryWriter &vis, const char *, T &v) {
reflect(vis, v);
}
// API
const char *Intern(llvm::StringRef str);
llvm::CachedHashStringRef InternH(llvm::StringRef str);
std::string Serialize(SerializeFormat format, IndexFile &file);
const char *intern(llvm::StringRef str);
llvm::CachedHashStringRef internH(llvm::StringRef str);
std::string serialize(SerializeFormat format, IndexFile &file);
std::unique_ptr<IndexFile>
Deserialize(SerializeFormat format, const std::string &path,
deserialize(SerializeFormat format, const std::string &path,
const std::string &serialized_index_content,
const std::string &file_content,
std::optional<int> expected_version);

View File

@ -3,16 +3,16 @@
#include "test.hh"
#include "sema_manager.hh"
#include "filesystem.hh"
#include "indexer.hh"
#include "pipeline.hh"
#include "platform.hh"
#include "sema_manager.hh"
#include "serializer.hh"
#include "utils.hh"
#include <llvm/Config/llvm-config.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Config/llvm-config.h>
#include <rapidjson/document.h>
#include <rapidjson/prettywriter.h>
@ -34,7 +34,7 @@ using namespace llvm;
extern bool gTestOutputMode;
namespace ccls {
std::string ToString(const rapidjson::Document &document) {
std::string toString(const rapidjson::Document &document) {
rapidjson::StringBuffer buffer;
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
writer.SetFormatOptions(
@ -54,7 +54,7 @@ struct TextReplacer {
std::vector<Replacement> replacements;
std::string Apply(const std::string &content) {
std::string apply(const std::string &content) {
std::string result = content;
for (const Replacement &replacement : replacements) {
@ -73,13 +73,13 @@ struct TextReplacer {
}
};
void TrimInPlace(std::string &s) {
void trimInPlace(std::string &s) {
auto f = [](char c) { return !isspace(c); };
s.erase(s.begin(), std::find_if(s.begin(), s.end(), f));
s.erase(std::find_if(s.rbegin(), s.rend(), f).base(), s.end());
}
std::vector<std::string> SplitString(const std::string &str,
std::vector<std::string> splitString(const std::string &str,
const std::string &delimiter) {
// http://stackoverflow.com/a/13172514
std::vector<std::string> strings;
@ -97,7 +97,7 @@ std::vector<std::string> SplitString(const std::string &str,
return strings;
}
void ParseTestExpectation(
void parseTestExpectation(
const std::string &filename,
const std::vector<std::string> &lines_with_endings, TextReplacer *replacer,
std::vector<std::string> *flags,
@ -161,7 +161,7 @@ void ParseTestExpectation(
}
}
void UpdateTestExpectation(const std::string &filename,
void updateTestExpectation(const std::string &filename,
const std::string &expectation,
const std::string &actual) {
// Read the entire file into a string.
@ -177,13 +177,13 @@ void UpdateTestExpectation(const std::string &filename,
str.replace(it, expectation.size(), actual);
// Write it back out.
WriteToFile(filename, str);
writeToFile(filename, str);
}
void DiffDocuments(std::string path, std::string path_section,
void diffDocuments(std::string path, std::string path_section,
rapidjson::Document &expected, rapidjson::Document &actual) {
std::string joined_actual_output = ToString(actual);
std::string joined_expected_output = ToString(expected);
std::string joined_actual_output = toString(actual);
std::string joined_expected_output = toString(expected);
printf("[FAILED] %s (section %s)\n", path.c_str(), path_section.c_str());
#if _POSIX_C_SOURCE >= 200809L
@ -210,9 +210,9 @@ void DiffDocuments(std::string path, std::string path_section,
}
#endif
std::vector<std::string> actual_output =
SplitString(joined_actual_output, "\n");
splitString(joined_actual_output, "\n");
std::vector<std::string> expected_output =
SplitString(joined_expected_output, "\n");
splitString(joined_expected_output, "\n");
printf("Expected output for %s (section %s)\n:%s\n", path.c_str(),
path_section.c_str(), joined_expected_output.c_str());
@ -220,20 +220,20 @@ void DiffDocuments(std::string path, std::string path_section,
path_section.c_str(), joined_actual_output.c_str());
}
void VerifySerializeToFrom(IndexFile *file) {
std::string expected = file->ToString();
std::string serialized = ccls::Serialize(SerializeFormat::Json, *file);
void verifySerializeToFrom(IndexFile *file) {
std::string expected = file->toString();
std::string serialized = ccls::serialize(SerializeFormat::Json, *file);
std::unique_ptr<IndexFile> result =
ccls::Deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
ccls::deserialize(SerializeFormat::Json, "--.cc", serialized, "<empty>",
std::nullopt /*expected_version*/);
std::string actual = result->ToString();
std::string actual = result->toString();
if (expected != actual) {
fprintf(stderr, "Serialization failure\n");
// assert(false);
}
}
std::string FindExpectedOutputForFilename(
std::string findExpectedOutputForFilename(
std::string filename,
const std::unordered_map<std::string, std::string> &expected) {
for (const auto &entry : expected) {
@ -248,7 +248,7 @@ std::string FindExpectedOutputForFilename(
}
IndexFile *
FindDbForPathEnding(const std::string &path,
findDbForPathEnding(const std::string &path,
const std::vector<std::unique_ptr<IndexFile>> &dbs) {
for (auto &db : dbs) {
if (StringRef(db->path).endswith(path))
@ -257,7 +257,7 @@ FindDbForPathEnding(const std::string &path,
return nullptr;
}
bool RunIndexTests(const std::string &filter_path, bool enable_update) {
bool runIndexTests(const std::string &filter_path, bool enable_update) {
gTestOutputMode = true;
std::string version = LLVM_VERSION_STRING;
@ -279,7 +279,7 @@ bool RunIndexTests(const std::string &filter_path, bool enable_update) {
SemaManager completion(
nullptr, nullptr, [&](std::string, std::vector<Diagnostic>) {},
[](RequestId id) {});
GetFilesInFolder(
getFilesInFolder(
"index_tests", true /*recursive*/, true /*add_folder_to_path*/,
[&](const std::string &path) {
bool is_fail_allowed = false;
@ -300,11 +300,11 @@ bool RunIndexTests(const std::string &filter_path, bool enable_update) {
TextReplacer text_replacer;
std::vector<std::string> flags;
std::unordered_map<std::string, std::string> all_expected_output;
ParseTestExpectation(path, lines_with_endings, &text_replacer, &flags,
parseTestExpectation(path, lines_with_endings, &text_replacer, &flags,
&all_expected_output);
// Build flags.
flags.push_back("-resource-dir=" + GetDefaultResourceDirectory());
flags.push_back("-resource-dir=" + getDefaultResourceDirectory());
flags.push_back(path);
// Run test.
@ -315,21 +315,21 @@ bool RunIndexTests(const std::string &filter_path, bool enable_update) {
for (auto &arg : flags)
cargs.push_back(arg.c_str());
bool ok;
auto dbs = ccls::idx::Index(&completion, &wfiles, &vfs, "", path, cargs,
auto dbs = ccls::idx::index(&completion, &wfiles, &vfs, "", path, cargs,
{}, true, ok);
for (const auto &entry : all_expected_output) {
const std::string &expected_path = entry.first;
std::string expected_output = text_replacer.Apply(entry.second);
std::string expected_output = text_replacer.apply(entry.second);
// Get output from index operation.
IndexFile *db = FindDbForPathEnding(expected_path, dbs);
IndexFile *db = findDbForPathEnding(expected_path, dbs);
std::string actual_output = "{}";
if (db) {
VerifySerializeToFrom(db);
actual_output = db->ToString();
verifySerializeToFrom(db);
actual_output = db->toString();
}
actual_output = text_replacer.Apply(actual_output);
actual_output = text_replacer.apply(actual_output);
// Compare output via rapidjson::Document to ignore any formatting
// differences.
@ -343,7 +343,7 @@ bool RunIndexTests(const std::string &filter_path, bool enable_update) {
} else {
if (!is_fail_allowed)
success = false;
DiffDocuments(path, expected_path, expected, actual);
diffDocuments(path, expected_path, expected, actual);
puts("\n");
if (enable_update) {
printf("[Enter to continue - type u to update test, a to update "
@ -361,8 +361,8 @@ bool RunIndexTests(const std::string &filter_path, bool enable_update) {
// Note: we use |entry.second| instead of |expected_output|
// because
// |expected_output| has had text replacements applied.
UpdateTestExpectation(path, entry.second,
ToString(actual) + "\n");
updateTestExpectation(path, entry.second,
toString(actual) + "\n");
}
}
}

View File

@ -6,5 +6,5 @@
#include <string>
namespace ccls {
bool RunIndexTests(const std::string &filter_path, bool enable_update);
bool runIndexTests(const std::string &filter_path, bool enable_update);
}

View File

@ -22,7 +22,7 @@ template <typename Lockable> void lock(Lockable &l) { l.lock(); }
namespace ccls {
struct BaseThreadQueue {
virtual bool IsEmpty() = 0;
virtual bool isEmpty() = 0;
virtual ~BaseThreadQueue() = default;
};
@ -47,19 +47,19 @@ private:
struct MultiQueueWaiter {
std::condition_variable_any cv;
static bool HasState(std::initializer_list<BaseThreadQueue *> queues) {
static bool hasState(std::initializer_list<BaseThreadQueue *> queues) {
for (BaseThreadQueue *queue : queues) {
if (!queue->IsEmpty())
if (!queue->isEmpty())
return true;
}
return false;
}
template <typename... BaseThreadQueue>
bool Wait(std::atomic<bool> &quit, BaseThreadQueue... queues) {
bool wait(std::atomic<bool> &quit, BaseThreadQueue... queues) {
MultiQueueLock<BaseThreadQueue...> l(queues...);
while (!quit.load(std::memory_order_relaxed)) {
if (HasState({queues...}))
if (hasState({queues...}))
return false;
cv.wait(l);
}
@ -67,10 +67,10 @@ struct MultiQueueWaiter {
}
template <typename... BaseThreadQueue>
void WaitUntil(std::chrono::steady_clock::time_point t,
void waitUntil(std::chrono::steady_clock::time_point t,
BaseThreadQueue... queues) {
MultiQueueLock<BaseThreadQueue...> l(queues...);
if (!HasState({queues...}))
if (!hasState({queues...}))
cv.wait_until(l, t);
}
};
@ -85,25 +85,25 @@ public:
explicit ThreadedQueue(MultiQueueWaiter *waiter) : waiter_(waiter) {}
// Returns the number of elements in the queue. This is lock-free.
size_t Size() const { return total_count_; }
size_t size() const { return total_count_; }
// Add an element to the queue.
template <void (std::deque<T>::*push)(T &&)> void Push(T &&t, bool priority) {
template <void (std::deque<T>::*Push)(T &&)> void push(T &&t, bool priority) {
std::lock_guard<std::mutex> lock(mutex_);
if (priority)
(priority_.*push)(std::move(t));
(priority_.*Push)(std::move(t));
else
(queue_.*push)(std::move(t));
(queue_.*Push)(std::move(t));
++total_count_;
waiter_->cv.notify_one();
}
void PushBack(T &&t, bool priority = false) {
Push<&std::deque<T>::push_back>(std::move(t), priority);
void pushBack(T &&t, bool priority = false) {
push<&std::deque<T>::push_back>(std::move(t), priority);
}
// Return all elements in the queue.
std::vector<T> DequeueAll() {
std::vector<T> dequeueAll() {
std::lock_guard<std::mutex> lock(mutex_);
total_count_ = 0;
@ -123,10 +123,10 @@ public:
}
// Returns true if the queue is empty. This is lock-free.
bool IsEmpty() { return total_count_ == 0; }
bool isEmpty() { return total_count_ == 0; }
// Get the first element from the queue. Blocks until one is available.
T Dequeue() {
T dequeue() {
std::unique_lock<std::mutex> lock(mutex_);
waiter_->cv.wait(lock,
[&]() { return !priority_.empty() || !queue_.empty(); });
@ -144,7 +144,7 @@ public:
// Get the first element from the queue without blocking. Returns a null
// value if the queue is empty.
std::optional<T> TryPopFront() {
std::optional<T> tryPopFront() {
std::lock_guard<std::mutex> lock(mutex_);
auto execute = [&](std::deque<T> *q) {
auto val = std::move(q->front());
@ -159,7 +159,7 @@ public:
return std::nullopt;
}
template <typename Fn> void Iterate(Fn fn) {
template <typename Fn> void iterate(Fn fn) {
std::lock_guard<std::mutex> lock(mutex_);
for (auto &entry : priority_)
fn(entry);

View File

@ -39,7 +39,7 @@ Matcher::Matcher(const std::string &pattern)
Matcher::~Matcher() {}
bool Matcher::Matches(const std::string &text) const {
bool Matcher::matches(const std::string &text) const {
return std::regex_search(text, impl->regex, std::regex_constants::match_any);
}
@ -50,7 +50,7 @@ GroupMatch::GroupMatch(const std::vector<std::string> &whitelist,
params.type = MessageType::Error;
params.message =
"failed to parse EMCAScript regex " + pattern + " : " + what;
pipeline::Notify(window_showMessage, params);
pipeline::notify(window_showMessage, params);
};
for (const std::string &pattern : whitelist) {
try {
@ -68,13 +68,13 @@ GroupMatch::GroupMatch(const std::vector<std::string> &whitelist,
}
}
bool GroupMatch::Matches(const std::string &text,
bool GroupMatch::matches(const std::string &text,
std::string *blacklist_pattern) const {
for (const Matcher &m : whitelist)
if (m.Matches(text))
if (m.matches(text))
return true;
for (const Matcher &m : blacklist)
if (m.Matches(text)) {
if (m.matches(text)) {
if (blacklist_pattern)
*blacklist_pattern = m.pattern;
return false;
@ -82,7 +82,7 @@ bool GroupMatch::Matches(const std::string &text,
return true;
}
uint64_t HashUsr(llvm::StringRef s) {
uint64_t hashUsr(llvm::StringRef s) {
union {
uint64_t ret;
uint8_t out[8];
@ -95,7 +95,7 @@ uint64_t HashUsr(llvm::StringRef s) {
return ret;
}
std::string LowerPathIfInsensitive(const std::string &path) {
std::string lowerPathIfInsensitive(const std::string &path) {
#if defined(_WIN32)
std::string ret = path;
for (char &c : ret)
@ -106,12 +106,12 @@ std::string LowerPathIfInsensitive(const std::string &path) {
#endif
}
void EnsureEndsInSlash(std::string &path) {
void ensureEndsInSlash(std::string &path) {
if (path.empty() || path[path.size() - 1] != '/')
path += '/';
}
std::string EscapeFileName(std::string path) {
std::string escapeFileName(std::string path) {
bool slash = path.size() && path.back() == '/';
#ifdef _WIN32
std::replace(path.begin(), path.end(), ':', '@');
@ -122,22 +122,22 @@ std::string EscapeFileName(std::string path) {
return path;
}
std::string ResolveIfRelative(const std::string &directory,
std::string resolveIfRelative(const std::string &directory,
const std::string &path) {
if (sys::path::is_absolute(path))
return path;
SmallString<256> Ret;
sys::path::append(Ret, directory, path);
return NormalizePath(Ret.str());
SmallString<256> ret;
sys::path::append(ret, directory, path);
return normalizePath(ret.str());
}
std::string RealPath(const std::string &path) {
std::string realPath(const std::string &path) {
SmallString<256> buf;
sys::fs::real_path(path, buf);
return buf.empty() ? path : llvm::sys::path::convert_to_slash(buf);
}
bool NormalizeFolder(std::string &path) {
bool normalizeFolder(std::string &path) {
for (auto &[root, real] : g_config->workspaceFolders)
if (real.size() && llvm::StringRef(path).startswith(real)) {
path = root + path.substr(real.size());
@ -146,14 +146,14 @@ bool NormalizeFolder(std::string &path) {
return false;
}
std::optional<int64_t> LastWriteTime(const std::string &path) {
sys::fs::file_status Status;
if (sys::fs::status(path, Status))
std::optional<int64_t> lastWriteTime(const std::string &path) {
sys::fs::file_status status;
if (sys::fs::status(path, status))
return {};
return sys::toTimeT(Status.getLastModificationTime());
return sys::toTimeT(status.getLastModificationTime());
}
std::optional<std::string> ReadContent(const std::string &filename) {
std::optional<std::string> readContent(const std::string &filename) {
char buf[4096];
std::string ret;
FILE *f = fopen(filename.c_str(), "rb");
@ -166,7 +166,7 @@ std::optional<std::string> ReadContent(const std::string &filename) {
return ret;
}
void WriteToFile(const std::string &filename, const std::string &content) {
void writeToFile(const std::string &filename, const std::string &content) {
FILE *f = fopen(filename.c_str(), "wb");
if (!f ||
(content.size() && fwrite(content.c_str(), content.size(), 1, f) != 1)) {
@ -178,7 +178,7 @@ void WriteToFile(const std::string &filename, const std::string &content) {
// Find discontinous |search| in |content|.
// Return |found| and the count of skipped chars before found.
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
int reverseSubseqMatch(std::string_view pat, std::string_view text,
int case_sensitivity) {
if (case_sensitivity == 1)
case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
@ -193,5 +193,5 @@ int ReverseSubseqMatch(std::string_view pat, std::string_view text,
return -1;
}
std::string GetDefaultResourceDirectory() { return CLANG_RESOURCE_DIRECTORY; }
std::string getDefaultResourceDirectory() { return CLANG_RESOURCE_DIRECTORY; }
} // namespace ccls

View File

@ -25,7 +25,7 @@ struct Matcher {
Matcher(const std::string &pattern); // throw
Matcher(Matcher &&) = default;
~Matcher();
bool Matches(const std::string &text) const;
bool matches(const std::string &text) const;
};
struct GroupMatch {
@ -33,31 +33,31 @@ struct GroupMatch {
GroupMatch(const std::vector<std::string> &whitelist,
const std::vector<std::string> &blacklist);
bool Matches(const std::string &text,
bool matches(const std::string &text,
std::string *blacklist_pattern = nullptr) const;
};
uint64_t HashUsr(llvm::StringRef s);
uint64_t hashUsr(llvm::StringRef s);
std::string LowerPathIfInsensitive(const std::string &path);
std::string lowerPathIfInsensitive(const std::string &path);
// Ensures that |path| ends in a slash.
void EnsureEndsInSlash(std::string &path);
void ensureEndsInSlash(std::string &path);
// Converts a file path to one that can be used as filename.
// e.g. foo/bar.c => foo_bar.c
std::string EscapeFileName(std::string path);
std::string escapeFileName(std::string path);
std::string ResolveIfRelative(const std::string &directory,
std::string resolveIfRelative(const std::string &directory,
const std::string &path);
std::string RealPath(const std::string &path);
bool NormalizeFolder(std::string &path);
std::string realPath(const std::string &path);
bool normalizeFolder(std::string &path);
std::optional<int64_t> LastWriteTime(const std::string &path);
std::optional<std::string> ReadContent(const std::string &filename);
void WriteToFile(const std::string &filename, const std::string &content);
std::optional<int64_t> lastWriteTime(const std::string &path);
std::optional<std::string> readContent(const std::string &filename);
void writeToFile(const std::string &filename, const std::string &content);
int ReverseSubseqMatch(std::string_view pat, std::string_view text,
int reverseSubseqMatch(std::string_view pat, std::string_view text,
int case_sensitivity);
// http://stackoverflow.com/a/38140932
@ -89,10 +89,10 @@ inline void hash_combine(std::size_t &seed, const T &v, Rest... rest) {
}; \
}
std::string GetDefaultResourceDirectory();
std::string getDefaultResourceDirectory();
// Like std::optional, but the stored data is responsible for containing the
// empty state. T should define a function `bool T::Valid()`.
// empty state. T should define a function `bool T::valid()`.
template <typename T> class Maybe {
T storage;
@ -114,10 +114,10 @@ public:
const T &operator*() const { return storage; }
T &operator*() { return storage; }
bool Valid() const { return storage.Valid(); }
explicit operator bool() const { return Valid(); }
bool valid() const { return storage.valid(); }
explicit operator bool() const { return valid(); }
operator std::optional<T>() const {
if (Valid())
if (valid())
return storage;
return std::nullopt;
}
@ -132,7 +132,8 @@ public:
template <typename T> struct Vec {
std::unique_ptr<T[]> a;
int s = 0;
#if !(__clang__ || __GNUC__ > 7 || __GNUC__ == 7 && __GNUC_MINOR__ >= 4) || defined(_WIN32)
#if !(__clang__ || __GNUC__ > 7 || __GNUC__ == 7 && __GNUC_MINOR__ >= 4) || \
defined(_WIN32)
// Work around a bug in GCC<7.4 that optional<IndexUpdate> would not be
// construtible.
Vec() = default;

View File

@ -27,7 +27,7 @@ constexpr int kMaxDiff = 20;
// |kMaxColumnAlignSize|.
constexpr int kMaxColumnAlignSize = 200;
Position GetPositionForOffset(const std::string &content, int offset) {
Position getPositionForOffset(const std::string &content, int offset) {
if (offset >= content.size())
offset = (int)content.size() - 1;
@ -42,7 +42,7 @@ Position GetPositionForOffset(const std::string &content, int offset) {
return {line, col};
}
std::vector<std::string> ToLines(const std::string &c) {
std::vector<std::string> toLines(const std::string &c) {
std::vector<std::string> ret;
int last = 0, e = c.size();
for (int i = 0; i < e; i++)
@ -59,7 +59,7 @@ std::vector<std::string> ToLines(const std::string &c) {
// Myers' O(ND) diff algorithm.
// Costs: insertion=1, deletion=1, no substitution.
// If the distance is larger than threshold, returns threshould + 1.
int MyersDiff(const char *a, int la, const char *b, int lb, int threshold) {
int myersDiff(const char *a, int la, const char *b, int lb, int threshold) {
assert(threshold <= kMaxDiff);
static int v_static[2 * kMaxColumnAlignSize + 2];
const char *ea = a + la, *eb = b + lb;
@ -94,8 +94,8 @@ int MyersDiff(const char *a, int la, const char *b, int lb, int threshold) {
return threshold + 1;
}
int MyersDiff(const std::string &a, const std::string &b, int threshold) {
return MyersDiff(a.data(), a.size(), b.data(), b.size(), threshold);
int myersDiff(const std::string &a, const std::string &b, int threshold) {
return myersDiff(a.data(), a.size(), b.data(), b.size(), threshold);
}
// Computes edit distance with O(N*M) Needleman-Wunsch algorithm
@ -104,7 +104,7 @@ int MyersDiff(const std::string &a, const std::string &b, int threshold) {
// Myers' diff algorithm is used to find best matching line while this one is
// used to align a single column because Myers' needs some twiddling to return
// distance vector.
std::vector<int> EditDistanceVector(std::string a, std::string b) {
std::vector<int> editDistanceVector(std::string a, std::string b) {
std::vector<int> d(b.size() + 1);
std::iota(d.begin(), d.end(), 0);
for (int i = 0; i < (int)a.size(); i++) {
@ -121,7 +121,7 @@ std::vector<int> EditDistanceVector(std::string a, std::string b) {
// Find matching position of |a[column]| in |b|.
// This is actually a single step of Hirschberg's sequence alignment algorithm.
int AlignColumn(const std::string &a, int column, std::string b, bool is_end) {
int alignColumn(const std::string &a, int column, std::string b, bool is_end) {
int head = 0, tail = 0;
while (head < (int)a.size() && head < (int)b.size() && a[head] == b[head])
head++;
@ -139,14 +139,14 @@ int AlignColumn(const std::string &a, int column, std::string b, bool is_end) {
b = b.substr(head, b.size() - tail - head);
// left[i] = cost of aligning a[head, column) to b[head, head + i)
std::vector<int> left = EditDistanceVector(a.substr(head, column - head), b);
std::vector<int> left = editDistanceVector(a.substr(head, column - head), b);
// right[i] = cost of aligning a[column, a.size() - tail) to b[head + i,
// b.size() - tail)
std::string a_rev = a.substr(column, a.size() - tail - column);
std::reverse(a_rev.begin(), a_rev.end());
std::reverse(b.begin(), b.end());
std::vector<int> right = EditDistanceVector(a_rev, b);
std::vector<int> right = editDistanceVector(a_rev, b);
std::reverse(right.begin(), right.end());
int best = 0, best_cost = INT_MAX;
@ -164,7 +164,7 @@ int AlignColumn(const std::string &a, int column, std::string b, bool is_end) {
// By symmetry, this can also be used to find matching index line of a buffer
// line.
std::optional<int>
FindMatchingLine(const std::vector<std::string> &index_lines,
findMatchingLine(const std::vector<std::string> &index_lines,
const std::vector<int> &index_to_buffer, int line, int *column,
const std::vector<std::string> &buffer_lines, bool is_end) {
// If this is a confident mapping, returns.
@ -172,7 +172,7 @@ FindMatchingLine(const std::vector<std::string> &index_lines,
int ret = index_to_buffer[line];
if (column)
*column =
AlignColumn(index_lines[line], *column, buffer_lines[ret], is_end);
alignColumn(index_lines[line], *column, buffer_lines[ret], is_end);
return ret;
}
@ -193,7 +193,7 @@ FindMatchingLine(const std::vector<std::string> &index_lines,
int best = up, best_dist = kMaxDiff + 1;
const std::string &needle = index_lines[line];
for (int i = up; i <= down; i++) {
int dist = MyersDiff(needle, buffer_lines[i], kMaxDiff);
int dist = myersDiff(needle, buffer_lines[i], kMaxDiff);
if (dist < best_dist) {
best_dist = dist;
best = i;
@ -201,7 +201,7 @@ FindMatchingLine(const std::vector<std::string> &index_lines,
}
if (column)
*column =
AlignColumn(index_lines[line], *column, buffer_lines[best], is_end);
alignColumn(index_lines[line], *column, buffer_lines[best], is_end);
return best;
}
@ -210,20 +210,20 @@ FindMatchingLine(const std::vector<std::string> &index_lines,
WorkingFile::WorkingFile(const std::string &filename,
const std::string &buffer_content)
: filename(filename), buffer_content(buffer_content) {
OnBufferContentUpdated();
onBufferContentUpdated();
// SetIndexContent gets called when the file is opened.
// setIndexContent gets called when the file is opened.
}
void WorkingFile::SetIndexContent(const std::string &index_content) {
index_lines = ToLines(index_content);
void WorkingFile::setIndexContent(const std::string &index_content) {
index_lines = toLines(index_content);
index_to_buffer.clear();
buffer_to_index.clear();
}
void WorkingFile::OnBufferContentUpdated() {
buffer_lines = ToLines(buffer_content);
void WorkingFile::onBufferContentUpdated() {
buffer_lines = toLines(buffer_content);
index_to_buffer.clear();
buffer_to_index.clear();
@ -235,7 +235,7 @@ void WorkingFile::OnBufferContentUpdated() {
// we are confident that the line appeared in index maps to the one appeared in
// buffer. And then using them as start points to extend upwards and downwards
// to align other identical lines (but not unique).
void WorkingFile::ComputeLineMapping() {
void WorkingFile::computeLineMapping() {
std::unordered_map<uint64_t, int> hash_to_unique;
std::vector<uint64_t> index_hashes(index_lines.size());
std::vector<uint64_t> buffer_hashes(buffer_lines.size());
@ -247,7 +247,7 @@ void WorkingFile::ComputeLineMapping() {
// For index line i, set index_to_buffer[i] to -1 if line i is duplicated.
int i = 0;
for (StringRef line : index_lines) {
uint64_t h = HashUsr(line);
uint64_t h = hashUsr(line);
auto it = hash_to_unique.find(h);
if (it == hash_to_unique.end()) {
hash_to_unique[h] = i;
@ -264,7 +264,7 @@ void WorkingFile::ComputeLineMapping() {
i = 0;
hash_to_unique.clear();
for (StringRef line : buffer_lines) {
uint64_t h = HashUsr(line);
uint64_t h = hashUsr(line);
auto it = hash_to_unique.find(h);
if (it == hash_to_unique.end()) {
hash_to_unique[h] = i;
@ -312,7 +312,7 @@ void WorkingFile::ComputeLineMapping() {
buffer_to_index[index_to_buffer[i]] = i;
}
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
std::optional<int> WorkingFile::getBufferPosFromIndexPos(int line, int *column,
bool is_end) {
if (line == (int)index_lines.size() && !*column)
return buffer_content.size();
@ -323,25 +323,25 @@ std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
}
if (index_to_buffer.empty())
ComputeLineMapping();
return FindMatchingLine(index_lines, index_to_buffer, line, column,
computeLineMapping();
return findMatchingLine(index_lines, index_to_buffer, line, column,
buffer_lines, is_end);
}
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, int *column,
std::optional<int> WorkingFile::getIndexPosFromBufferPos(int line, int *column,
bool is_end) {
if (line < 0 || line >= (int)buffer_lines.size())
return std::nullopt;
if (buffer_to_index.empty())
ComputeLineMapping();
return FindMatchingLine(buffer_lines, buffer_to_index, line, column,
computeLineMapping();
return findMatchingLine(buffer_lines, buffer_to_index, line, column,
index_lines, is_end);
}
Position WorkingFile::GetCompletionPosition(Position pos, std::string *filter,
Position WorkingFile::getCompletionPosition(Position pos, std::string *filter,
Position *replace_end_pos) const {
int start = GetOffsetForPosition(pos, buffer_content);
int start = getOffsetForPosition(pos, buffer_content);
int i = start;
while (i > 0 && isIdentifierBody(buffer_content[i - 1]))
--i;
@ -352,47 +352,47 @@ Position WorkingFile::GetCompletionPosition(Position pos, std::string *filter,
replace_end_pos->character++;
*filter = buffer_content.substr(i, start - i);
return GetPositionForOffset(buffer_content, i);
return getPositionForOffset(buffer_content, i);
}
WorkingFile *WorkingFiles::GetFile(const std::string &path) {
WorkingFile *WorkingFiles::getFile(const std::string &path) {
std::lock_guard lock(mutex);
return GetFileUnlocked(path);
return getFileUnlocked(path);
}
WorkingFile *WorkingFiles::GetFileUnlocked(const std::string &path) {
WorkingFile *WorkingFiles::getFileUnlocked(const std::string &path) {
auto it = files.find(path);
return it != files.end() ? it->second.get() : nullptr;
}
std::string WorkingFiles::GetContent(const std::string &path) {
std::string WorkingFiles::getContent(const std::string &path) {
std::lock_guard lock(mutex);
auto it = files.find(path);
return it != files.end() ? it->second->buffer_content : "";
}
WorkingFile *WorkingFiles::OnOpen(const TextDocumentItem &open) {
WorkingFile *WorkingFiles::onOpen(const TextDocumentItem &open) {
std::lock_guard lock(mutex);
std::string path = open.uri.GetPath();
std::string path = open.uri.getPath();
std::string content = open.text;
auto &wf = files[path];
if (wf) {
wf->version = open.version;
wf->buffer_content = content;
wf->OnBufferContentUpdated();
wf->onBufferContentUpdated();
} else {
wf = std::make_unique<WorkingFile>(path, content);
}
return wf.get();
}
void WorkingFiles::OnChange(const TextDocumentDidChangeParam &change) {
void WorkingFiles::onChange(const TextDocumentDidChangeParam &change) {
std::lock_guard lock(mutex);
std::string path = change.textDocument.uri.GetPath();
WorkingFile *file = GetFileUnlocked(path);
std::string path = change.textDocument.uri.getPath();
WorkingFile *file = getFileUnlocked(path);
if (!file) {
LOG_S(WARNING) << "Could not change " << path << " because it was not open";
return;
@ -411,23 +411,23 @@ void WorkingFiles::OnChange(const TextDocumentDidChangeParam &change) {
// See https://github.com/Microsoft/language-server-protocol/issues/9.
if (!diff.range) {
file->buffer_content = diff.text;
file->OnBufferContentUpdated();
file->onBufferContentUpdated();
} else {
int start_offset =
GetOffsetForPosition(diff.range->start, file->buffer_content);
getOffsetForPosition(diff.range->start, file->buffer_content);
// Ignore TextDocumentContentChangeEvent.rangeLength which causes trouble
// when UTF-16 surrogate pairs are used.
int end_offset =
GetOffsetForPosition(diff.range->end, file->buffer_content);
getOffsetForPosition(diff.range->end, file->buffer_content);
file->buffer_content.replace(file->buffer_content.begin() + start_offset,
file->buffer_content.begin() + end_offset,
diff.text);
file->OnBufferContentUpdated();
file->onBufferContentUpdated();
}
}
}
void WorkingFiles::OnClose(const std::string &path) {
void WorkingFiles::onClose(const std::string &path) {
std::lock_guard lock(mutex);
files.erase(path);
}
@ -436,7 +436,7 @@ void WorkingFiles::OnClose(const std::string &path) {
// text documents.
// We use a UTF-8 iterator to approximate UTF-16 in the specification (weird).
// This is good enough and fails only for UTF-16 surrogate pairs.
int GetOffsetForPosition(Position pos, std::string_view content) {
int getOffsetForPosition(Position pos, std::string_view content) {
size_t i = 0;
for (; pos.line > 0 && i < content.size(); i++)
if (content[i] == '\n')
@ -452,9 +452,9 @@ int GetOffsetForPosition(Position pos, std::string_view content) {
return int(i);
}
std::string_view LexIdentifierAroundPos(Position position,
std::string_view lexIdentifierAroundPos(Position position,
std::string_view content) {
int start = GetOffsetForPosition(position, content), end = start + 1;
int start = getOffsetForPosition(position, content), end = start + 1;
char c;
// We search for :: before the cursor but not after to get the qualifier.
@ -470,4 +470,4 @@ std::string_view LexIdentifierAroundPos(Position position,
return content.substr(start, end - start);
}
}
} // namespace ccls

View File

@ -36,50 +36,50 @@ struct WorkingFile {
WorkingFile(const std::string &filename, const std::string &buffer_content);
// This should be called when the indexed content has changed.
void SetIndexContent(const std::string &index_content);
void setIndexContent(const std::string &index_content);
// This should be called whenever |buffer_content| has changed.
void OnBufferContentUpdated();
void onBufferContentUpdated();
// Finds the buffer line number which maps to index line number |line|.
// Also resolves |column| if not NULL.
// When resolving a range, use is_end = false for begin() and is_end =
// true for end() to get a better alignment of |column|.
std::optional<int> GetBufferPosFromIndexPos(int line, int *column,
std::optional<int> getBufferPosFromIndexPos(int line, int *column,
bool is_end);
// Finds the index line number which maps to buffer line number |line|.
// Also resolves |column| if not NULL.
std::optional<int> GetIndexPosFromBufferPos(int line, int *column,
std::optional<int> getIndexPosFromBufferPos(int line, int *column,
bool is_end);
// Returns the stable completion position (it jumps back until there is a
// non-alphanumeric character).
Position GetCompletionPosition(Position pos, std::string *filter,
Position getCompletionPosition(Position pos, std::string *filter,
Position *replace_end_pos) const;
private:
// Compute index_to_buffer and buffer_to_index.
void ComputeLineMapping();
void computeLineMapping();
};
struct WorkingFiles {
WorkingFile *GetFile(const std::string &path);
WorkingFile *GetFileUnlocked(const std::string &path);
std::string GetContent(const std::string &path);
WorkingFile *getFile(const std::string &path);
WorkingFile *getFileUnlocked(const std::string &path);
std::string getContent(const std::string &path);
template <typename Fn> void WithLock(Fn &&fn) {
template <typename Fn> void withLock(Fn &&fn) {
std::lock_guard lock(mutex);
fn();
}
WorkingFile *OnOpen(const TextDocumentItem &open);
void OnChange(const TextDocumentDidChangeParam &change);
void OnClose(const std::string &close);
WorkingFile *onOpen(const TextDocumentItem &open);
void onChange(const TextDocumentDidChangeParam &change);
void onClose(const std::string &close);
std::mutex mutex;
std::unordered_map<std::string, std::unique_ptr<WorkingFile>> files;
};
int GetOffsetForPosition(Position pos, std::string_view content);
int getOffsetForPosition(Position pos, std::string_view content);
std::string_view LexIdentifierAroundPos(Position position,
std::string_view lexIdentifierAroundPos(Position position,
std::string_view content);
} // namespace ccls