Skip to content

Commit

Permalink
Support workspaces as symlinks and symlinks within a workspace
Browse files Browse the repository at this point in the history
Fix #639
  • Loading branch information
MaskRay committed Jul 20, 2020
1 parent 5108cfa commit ca95f48
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 12 deletions.
22 changes: 16 additions & 6 deletions src/clang_tu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,22 @@ 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);
// Resolve symlinks outside of workspace folders, e.g. /usr/include/c++/7.3.0
return normalizeFolder(ret) ? ret : realPath(ret);
std::string ret;
if (file.getName().startswith("/../")) {
// Resolve symlinks outside of working folders. This handles leading path
// components, e.g. (/lib -> /usr/lib) in
// /../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/utility
ret = file.tryGetRealPathName();
} else {
// If getName() refers to a file within a workspace folder, we prefer it
// (which may be a symlink).
ret = normalizePath(file.getName());
}
if (normalizeFolder(ret))
return ret;
ret = realPath(ret);
normalizeFolder(ret);
return ret;
}

bool isInsideMainFile(const SourceManager &sm, SourceLocation sl) {
Expand Down
7 changes: 3 additions & 4 deletions src/messages/initialize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -348,17 +348,16 @@ void do_initialize(MessageHandler *m, InitializeParam &param,
std::string path = wf.uri.getPath();
ensureEndsInSlash(path);
std::string real = realPath(path) + '/';
workspaceFolders.emplace_back(path, path == real ? "" : real);
workspaceFolders.emplace_back(path, real);
}
if (workspaceFolders.empty()) {
std::string real = realPath(project_path) + '/';
workspaceFolders.emplace_back(project_path,
project_path == real ? "" : real);
workspaceFolders.emplace_back(project_path, real);
}
std::sort(workspaceFolders.begin(), workspaceFolders.end(),
[](auto &l, auto &r) { return l.first.size() > r.first.size(); });
for (auto &[folder, real] : workspaceFolders)
if (real.empty())
if (real == folder)
LOG_S(INFO) << "workspace folder: " << folder;
else
LOG_S(INFO) << "workspace folder: " << folder << " -> " << real;
Expand Down
2 changes: 2 additions & 0 deletions src/project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,9 @@ void Project::loadDirectory(const std::string &root, Project::Folder &folder) {
// If workspace folder is real/ but entries use symlink/, convert to
// real/.
entry.directory = realPath(cmd.Directory);
entry.directory.push_back('/');
normalizeFolder(entry.directory);
entry.directory.pop_back();
doPathMapping(entry.directory);
entry.filename =
realPath(resolveIfRelative(entry.directory, cmd.Filename));
Expand Down
8 changes: 6 additions & 2 deletions src/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,15 @@ std::string realPath(const std::string &path) {
}

bool normalizeFolder(std::string &path) {
for (auto &[root, real] : g_config->workspaceFolders)
if (real.size() && llvm::StringRef(path).startswith(real)) {
for (auto &[root, real] : g_config->workspaceFolders) {
StringRef p(path);
if (p.startswith(root))
return true;
if (p.startswith(real)) {

This comment has been minimized.

Copy link
@damnskippy

damnskippy Jan 8, 2021

Should this be conditional on real.size() being non-zero? Looks like this check was there before the change.

path = root + path.substr(real.size());
return true;
}
}
return false;
}

Expand Down

1 comment on commit ca95f48

@damnskippy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was running into a problem where even absolute path names (from compile_commands.json file) were getting prefixed with root path. i.e. file '/path/to/file.foo' will become '/path/to/root//path/to/file.foo'
In debugging why my setup stopped working after I upgraded to latest, I found this commit to be the potential reason why.
I noticed there are times real.size() is 0 and the code then concatenates root with the path here:
path = root + path.substr(real.size());
Adding the real.size() check and concatenating only when non-zero seemed to fix my issues.
Thanks for a great server implementation.

Please sign in to comment.