mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-24 08:35:08 +00:00
Refactor FindEntry and use best-fit .ccls
Fixes an issue with hierarchical .ccls found by Riatre in #384
This commit is contained in:
parent
16bd93b24b
commit
6624108fd9
188
src/project.cc
188
src/project.cc
@ -240,8 +240,6 @@ std::vector<const char *> GetFallback(const std::string path) {
|
|||||||
std::vector<const char *> argv{"clang"};
|
std::vector<const char *> argv{"clang"};
|
||||||
if (sys::path::extension(path) == ".h")
|
if (sys::path::extension(path) == ".h")
|
||||||
argv.push_back("-xobjective-c++-header");
|
argv.push_back("-xobjective-c++-header");
|
||||||
for (const std::string &arg : g_config->clang.extraArgs)
|
|
||||||
argv.push_back(Intern(arg));
|
|
||||||
argv.push_back(Intern(path));
|
argv.push_back(Intern(path));
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
@ -442,13 +440,6 @@ void Project::LoadDirectory(const std::string &root, Project::Folder &folder) {
|
|||||||
sys::path::append(Path, root, ".ccls");
|
sys::path::append(Path, root, ".ccls");
|
||||||
if (sys::fs::exists(Path))
|
if (sys::fs::exists(Path))
|
||||||
LoadDirectoryListing(proc, root, Seen);
|
LoadDirectoryListing(proc, root, Seen);
|
||||||
std::vector<const char *> extra_args;
|
|
||||||
for (const std::string &arg : g_config->clang.extraArgs)
|
|
||||||
extra_args.push_back(Intern(arg));
|
|
||||||
for (auto &e : folder.entries) {
|
|
||||||
e.args.insert(e.args.end(), extra_args.begin(), extra_args.end());
|
|
||||||
e.args.push_back(Intern("-working-directory=" + e.directory));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::Load(const std::string &root) {
|
void Project::Load(const std::string &root) {
|
||||||
@ -470,94 +461,106 @@ 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) {
|
bool must_exist) {
|
||||||
Project::Folder *best_folder = nullptr;
|
std::string best_dot_ccls_root;
|
||||||
|
Project::Folder *best_dot_ccls_folder = nullptr;
|
||||||
|
std::string best_dot_ccls_dir;
|
||||||
|
const std::vector<const char *> *best_dot_ccls_args = nullptr;
|
||||||
|
|
||||||
|
bool match = false, exact_match = false;
|
||||||
const Entry *best = nullptr;
|
const Entry *best = nullptr;
|
||||||
std::lock_guard lock(mtx);
|
Project::Folder *best_compdb_folder = nullptr;
|
||||||
for (auto &[root, folder] : root2folder) {
|
|
||||||
// The entry may have different filename but it doesn't matter when building
|
|
||||||
// CompilerInvocation. The main filename is specified separately.
|
|
||||||
auto it = folder.path2entry_index.find(path);
|
|
||||||
if (it != folder.path2entry_index.end()) {
|
|
||||||
Project::Entry &entry = folder.entries[it->second];
|
|
||||||
if (can_redirect || entry.filename == path)
|
|
||||||
return entry;
|
|
||||||
if (entry.compdb_size) {
|
|
||||||
best_folder = &folder;
|
|
||||||
best = &entry;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool exists = false;
|
|
||||||
std::string dir;
|
|
||||||
const std::vector<const char *> *extra = nullptr;
|
|
||||||
Project::Entry ret;
|
Project::Entry ret;
|
||||||
|
std::lock_guard lock(mtx);
|
||||||
|
|
||||||
for (auto &[root, folder] : root2folder)
|
for (auto &[root, folder] : root2folder)
|
||||||
if (StringRef(path).startswith(root))
|
if (StringRef(path).startswith(root)) {
|
||||||
for (auto &[dir1, args] : folder.dot_ccls)
|
// Find the best-fit .ccls
|
||||||
if (StringRef(path).startswith(dir1)) {
|
for (auto &[dir, args] : folder.dot_ccls)
|
||||||
dir = dir1;
|
if (StringRef(path).startswith(dir) &&
|
||||||
extra = &args;
|
dir.length() > best_dot_ccls_dir.length()) {
|
||||||
if (AppendToCDB(args))
|
best_dot_ccls_root = root;
|
||||||
goto out;
|
best_dot_ccls_folder = &folder;
|
||||||
exists = true;
|
best_dot_ccls_dir = dir;
|
||||||
|
best_dot_ccls_args = &args;
|
||||||
ret.root = ret.directory = root;
|
|
||||||
ret.filename = path;
|
|
||||||
if (args.empty()) {
|
|
||||||
ret.args = GetFallback(path);
|
|
||||||
} else {
|
|
||||||
ret.args = args;
|
|
||||||
ret.args.push_back(Intern(path));
|
|
||||||
}
|
|
||||||
ProjectProcessor(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));
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
out:
|
|
||||||
if (must_exist && !exists)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (!best) {
|
if (!match) {
|
||||||
int best_score = INT_MIN;
|
auto it = folder.path2entry_index.find(path);
|
||||||
for (auto &[root, folder] : root2folder) {
|
if (it != folder.path2entry_index.end()) {
|
||||||
if (dir.size() && !StringRef(path).startswith(dir))
|
Project::Entry &entry = folder.entries[it->second];
|
||||||
continue;
|
exact_match = entry.filename == path;
|
||||||
for (const Entry &e : folder.entries)
|
if ((match = exact_match || can_redirect) || entry.compdb_size) {
|
||||||
if (e.compdb_size) {
|
// best->compdb_size is >0 for a compdb entry, 0 for a .ccls entry.
|
||||||
int score = ComputeGuessScore(path, e.filename);
|
best_compdb_folder = &folder;
|
||||||
if (score > best_score) {
|
best = &entry;
|
||||||
best_score = score;
|
|
||||||
best = &e;
|
|
||||||
best_folder = &folder;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ret.is_inferred = true;
|
bool append;
|
||||||
ret.filename = path;
|
if (best_dot_ccls_args && !(append = AppendToCDB(*best_dot_ccls_args)) &&
|
||||||
if (!best) {
|
!exact_match) {
|
||||||
if (ret.root.empty())
|
// If the first line is not %compile_commands.json, override the compdb
|
||||||
ret.root = g_config->fallbackFolder;
|
// match if it is not an exact match.
|
||||||
ret.directory = ret.root;
|
ret.root = ret.directory = best_dot_ccls_root;
|
||||||
ret.args = GetFallback(path);
|
ret.filename = path;
|
||||||
|
if (best_dot_ccls_args->empty()) {
|
||||||
|
ret.args = GetFallback(path);
|
||||||
|
} else {
|
||||||
|
ret.args = *best_dot_ccls_args;
|
||||||
|
ret.args.push_back(Intern(path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret.root = best->root;
|
// If the first line is %compile_commands.json, find the matching compdb
|
||||||
ret.directory = best->directory;
|
// entry and append .ccls args.
|
||||||
ret.args = best->args;
|
if (must_exist && !match && !(best_dot_ccls_args && !append))
|
||||||
ret.args.resize(best->compdb_size);
|
return ret;
|
||||||
if (extra && extra->size())
|
if (!best) {
|
||||||
ret.args.insert(ret.args.end(), extra->begin() + 1, extra->end());
|
// Infer args from a similar path.
|
||||||
ProjectProcessor(*best_folder).Process(ret);
|
int best_score = INT_MIN;
|
||||||
for (const std::string &arg : g_config->clang.extraArgs)
|
for (auto &[root, folder] : root2folder)
|
||||||
ret.args.push_back(Intern(arg));
|
if (StringRef(path).startswith(root))
|
||||||
ret.args.push_back(Intern("-working-directory=" + ret.directory));
|
for (const Entry &e : folder.entries)
|
||||||
|
if (e.compdb_size) {
|
||||||
|
int score = ComputeGuessScore(path, e.filename);
|
||||||
|
if (score > best_score) {
|
||||||
|
best_score = score;
|
||||||
|
best_compdb_folder = &folder;
|
||||||
|
best = &e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret.is_inferred = true;
|
||||||
|
}
|
||||||
|
if (!best) {
|
||||||
|
ret.root = ret.directory = g_config->fallbackFolder;
|
||||||
|
ret.args = GetFallback(path);
|
||||||
|
} else {
|
||||||
|
// The entry may have different filename but it doesn't matter when
|
||||||
|
// building CompilerInvocation. The main filename is specified
|
||||||
|
// separately.
|
||||||
|
ret.root = best->root;
|
||||||
|
ret.directory = best->directory;
|
||||||
|
ret.args = best->args;
|
||||||
|
if (best->compdb_size) // delete trailing .ccls options if exist
|
||||||
|
ret.args.resize(best->compdb_size);
|
||||||
|
else
|
||||||
|
best_dot_ccls_args = nullptr;
|
||||||
|
}
|
||||||
|
ret.filename = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (best_dot_ccls_args && append && best_dot_ccls_args->size())
|
||||||
|
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);
|
||||||
|
else if (best_dot_ccls_folder)
|
||||||
|
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));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,6 +568,9 @@ void Project::Index(WorkingFiles *wfiles, RequestId id) {
|
|||||||
auto &gi = g_config->index;
|
auto &gi = g_config->index;
|
||||||
GroupMatch match(gi.whitelist, gi.blacklist),
|
GroupMatch match(gi.whitelist, gi.blacklist),
|
||||||
match_i(gi.initialWhitelist, gi.initialBlacklist);
|
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));
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mtx);
|
std::lock_guard lock(mtx);
|
||||||
for (auto &[root, folder] : root2folder) {
|
for (auto &[root, folder] : root2folder) {
|
||||||
@ -574,7 +580,10 @@ void Project::Index(WorkingFiles *wfiles, RequestId id) {
|
|||||||
if (match.Matches(entry.filename, &reason) &&
|
if (match.Matches(entry.filename, &reason) &&
|
||||||
match_i.Matches(entry.filename, &reason)) {
|
match_i.Matches(entry.filename, &reason)) {
|
||||||
bool interactive = wfiles->GetFile(entry.filename) != nullptr;
|
bool interactive = wfiles->GetFile(entry.filename) != nullptr;
|
||||||
pipeline::Index(entry.filename, entry.args,
|
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,
|
||||||
interactive ? IndexMode::Normal
|
interactive ? IndexMode::Normal
|
||||||
: IndexMode::Background,
|
: IndexMode::Background,
|
||||||
false, id);
|
false, id);
|
||||||
@ -597,15 +606,20 @@ void Project::IndexRelated(const std::string &path) {
|
|||||||
auto &gi = g_config->index;
|
auto &gi = g_config->index;
|
||||||
GroupMatch match(gi.whitelist, gi.blacklist);
|
GroupMatch match(gi.whitelist, gi.blacklist);
|
||||||
std::string stem = sys::path::stem(path);
|
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));
|
||||||
std::lock_guard lock(mtx);
|
std::lock_guard lock(mtx);
|
||||||
for (auto &[root, folder] : root2folder)
|
for (auto &[root, folder] : root2folder)
|
||||||
if (StringRef(path).startswith(root)) {
|
if (StringRef(path).startswith(root)) {
|
||||||
for (const Project::Entry &entry : folder.entries) {
|
for (const Project::Entry &entry : folder.entries) {
|
||||||
std::string reason;
|
std::string reason;
|
||||||
|
args = entry.args;
|
||||||
|
args.insert(args.end(), extra_args.begin(), extra_args.end());
|
||||||
|
args.push_back(Intern("-working-directory=" + entry.directory));
|
||||||
if (sys::path::stem(entry.filename) == stem && entry.filename != path &&
|
if (sys::path::stem(entry.filename) == stem && entry.filename != path &&
|
||||||
match.Matches(entry.filename, &reason))
|
match.Matches(entry.filename, &reason))
|
||||||
pipeline::Index(entry.filename, entry.args, IndexMode::Background,
|
pipeline::Index(entry.filename, args, IndexMode::Background, true);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user