glean/lang/clang/path.cpp (63 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "glean/lang/clang/path.h"
#include <algorithm>
#include <cassert>
namespace facebook {
namespace glean {
namespace clangx {
std::filesystem::path goodPath(
std::filesystem::path root,
std::filesystem::path path) {
assert(root.is_absolute());
path = path.lexically_normal();
// NOTE: we can't use std's lexically_relative because
// "../foo/bar".lexically_relative("/foo") isn't "bar".
if (path.is_relative()) {
auto root_begin = root.begin();
auto root_end = root.end();
auto path_begin = path.begin();
auto path_end = path.end();
auto done = false;
while (root_begin != root_end && path_begin != path_end && !done) {
if (*path_begin == "..") {
--root_end;
++path_begin;
} else if (root_end != root.end() && *path_begin == *root_end) {
++root_end;
++path_begin;
} else {
done = true;
}
}
std::filesystem::path result;
while (root_end != root.end()) {
result /= "..";
++root_end;
}
while (path_begin != path_end) {
result /= *path_begin;
++path_begin;
}
return result;
} else {
auto d = std::mismatch(
path.begin(), path.end(), root.begin(), root.end());
if (d.second == root.end()) {
std::filesystem::path ret;
for (auto i = d.first; i != path.end(); ++i) {
ret /= *i;
}
return ret;
} else {
return path;
}
}
}
std::filesystem::path betterPath(
std::filesystem::path path1,
std::filesystem::path path2) {
return
!path1.empty() && (path1.is_relative() || path2.is_absolute())
? path1
: path2;
}
}
}
}