Skip to content

Commit cb08df4

Browse files
committed
Support workspaces as symlinks and symlinks within a workspace
Fix #639
1 parent cb06cf1 commit cb08df4

File tree

4 files changed

+23
-12
lines changed

4 files changed

+23
-12
lines changed

src/clang_tu.cc

+12-6
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@
1717
#include <llvm/Support/Path.h>
1818

1919
using namespace clang;
20+
using namespace llvm;
2021

2122
namespace ccls {
2223
std::string pathFromFileEntry(const FileEntry &file) {
23-
StringRef name = file.tryGetRealPathName();
24-
if (name.empty())
25-
name = file.getName();
26-
std::string ret = normalizePath(name);
27-
// Resolve symlinks outside of workspace folders, e.g. /usr/include/c++/7.3.0
28-
return normalizeFolder(ret) ? ret : realPath(ret);
24+
// If getName() refers to a file within a workspace folder, we prefer it
25+
// (which may be a symlink).
26+
std::string ret = normalizePath(file.getName());
27+
if (normalizeFolder(ret))
28+
return ret;
29+
// Resolve symlinks outside of working folders. This handles leading path
30+
// components, e.g. (/lib -> /usr/lib) in
31+
// /../lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/utility
32+
ret = realPath(ret);
33+
normalizeFolder(ret);
34+
return ret;
2935
}
3036

3137
bool isInsideMainFile(const SourceManager &sm, SourceLocation sl) {

src/messages/initialize.cc

+3-4
Original file line numberDiff line numberDiff line change
@@ -348,17 +348,16 @@ void do_initialize(MessageHandler *m, InitializeParam &param,
348348
std::string path = wf.uri.getPath();
349349
ensureEndsInSlash(path);
350350
std::string real = realPath(path) + '/';
351-
workspaceFolders.emplace_back(path, path == real ? "" : real);
351+
workspaceFolders.emplace_back(path, real);
352352
}
353353
if (workspaceFolders.empty()) {
354354
std::string real = realPath(project_path) + '/';
355-
workspaceFolders.emplace_back(project_path,
356-
project_path == real ? "" : real);
355+
workspaceFolders.emplace_back(project_path, real);
357356
}
358357
std::sort(workspaceFolders.begin(), workspaceFolders.end(),
359358
[](auto &l, auto &r) { return l.first.size() > r.first.size(); });
360359
for (auto &[folder, real] : workspaceFolders)
361-
if (real.empty())
360+
if (real == folder)
362361
LOG_S(INFO) << "workspace folder: " << folder;
363362
else
364363
LOG_S(INFO) << "workspace folder: " << folder << " -> " << real;

src/project.cc

+2
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,9 @@ void Project::loadDirectory(const std::string &root, Project::Folder &folder) {
433433
// If workspace folder is real/ but entries use symlink/, convert to
434434
// real/.
435435
entry.directory = realPath(cmd.Directory);
436+
entry.directory.push_back('/');
436437
normalizeFolder(entry.directory);
438+
entry.directory.pop_back();
437439
doPathMapping(entry.directory);
438440
entry.filename =
439441
realPath(resolveIfRelative(entry.directory, cmd.Filename));

src/utils.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,15 @@ std::string realPath(const std::string &path) {
138138
}
139139

140140
bool normalizeFolder(std::string &path) {
141-
for (auto &[root, real] : g_config->workspaceFolders)
142-
if (real.size() && llvm::StringRef(path).startswith(real)) {
141+
for (auto &[root, real] : g_config->workspaceFolders) {
142+
StringRef p(path);
143+
if (p.startswith(root))
144+
return true;
145+
if (p.startswith(real)) {
143146
path = root + path.substr(real.size());
144147
return true;
145148
}
149+
}
146150
return false;
147151
}
148152

0 commit comments

Comments
 (0)