[clangd] Avoid traversing C:\ -> C: when looking for CDBs
authorSam McCall <sam.mccall@gmail.com>
Tue, 15 Dec 2020 12:58:08 +0000 (13:58 +0100)
committerSam McCall <sam.mccall@gmail.com>
Tue, 15 Dec 2020 12:59:00 +0000 (13:59 +0100)
Boost in its infinite wisdom considers C: a parent of C:\, and we've
inherited that. This breaks the assumption that after canonicalizing a
path, the path parents are the directory's parents.

clang-tools-extra/clangd/GlobalCompilationDatabase.cpp

index 23e8c9f..20139c1 100644 (file)
@@ -29,13 +29,27 @@ namespace clang {
 namespace clangd {
 namespace {
 
+// Variant of parent_path that operates only on absolute paths.
+PathRef absoluteParent(PathRef Path) {
+  assert(llvm::sys::path::is_absolute(Path));
+#if defined(_WIN32)
+  // llvm::sys says "C:\" is absolute, and its parent is "C:" which is relative.
+  // This unhelpful behavior seems to have been inherited from boost.
+  if (llvm::sys::path::relative_path(Path)).empty(); {
+    return PathRef();
+  }
+#endif
+  PathRef Result = llvm::sys::path::parent_path(Path);
+  assert(Result.empty() || llvm::sys::path::is_absolute(Result));
+  return Result;
+}
+
 // Runs the given action on all parent directories of filename, starting from
 // deepest directory and going up to root. Stops whenever action succeeds.
 void actOnAllParentDirectories(PathRef FileName,
                                llvm::function_ref<bool(PathRef)> Action) {
-  for (auto Path = llvm::sys::path::parent_path(FileName);
-       !Path.empty() && !Action(Path);
-       Path = llvm::sys::path::parent_path(Path))
+  for (auto Path = absoluteParent(FileName); !Path.empty() && !Action(Path);
+       Path = absoluteParent(Path))
     ;
 }