36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/StringExtras.h"
38#include "llvm/Support/Path.h"
50 llvm::SmallString<128> Result =
Path.rtrim(
'/');
51 native(Result, llvm::sys::path::Style::posix);
52 if (Result.empty() || Result.front() !=
'/')
53 Result.insert(Result.begin(),
'/');
59 llvm::hash_value(llvm::StringRef(
"/"));
64 llvm::DenseMap<llvm::hash_code, llvm::SmallVector<llvm::hash_code>> DownEdges;
67 for (
const auto &S : Sources) {
69 dlog(
"Source {0} = {1}, MaxUp = {2}", Canonical, S.second.Cost,
70 S.second.MaxUpTraversals);
72 llvm::StringRef Rest = Canonical;
73 llvm::hash_code Hash = llvm::hash_value(Rest);
74 for (
unsigned I = 0; !Rest.empty(); ++I) {
75 Rest = parent_path(Rest, llvm::sys::path::Style::posix);
76 auto NextHash = llvm::hash_value(Rest);
77 auto &Down = DownEdges[NextHash];
78 if (!llvm::is_contained(Down, Hash))
81 if (I > S.getValue().MaxUpTraversals) {
82 if (Cache.contains(Hash))
85 unsigned Cost = S.getValue().Cost + I * Opts.UpCost;
86 auto R = Cache.try_emplace(Hash, Cost);
88 if (Cost < R.first->second) {
89 R.first->second = Cost;
101 std::queue<llvm::hash_code> Next;
102 for (
auto Child : DownEdges.lookup(llvm::hash_value(llvm::StringRef(
""))))
104 while (!Next.empty()) {
105 auto Parent = Next.front();
107 auto ParentCost = Cache.lookup(
Parent);
108 for (
auto Child : DownEdges.lookup(
Parent)) {
111 Cache.try_emplace(Child,
Unreachable).first->getSecond();
112 if (ParentCost + Opts.DownCost < ChildCost)
113 ChildCost = ParentCost + Opts.DownCost;
123 llvm::SmallVector<llvm::hash_code> Ancestors;
125 for (llvm::StringRef Rest = Canonical; !Rest.empty();
126 Rest = parent_path(Rest, llvm::sys::path::Style::posix)) {
127 auto Hash = llvm::hash_value(Rest);
128 if (Hash ==
RootHash && !Ancestors.empty() &&
133 auto It = Cache.find(Hash);
134 if (It != Cache.end()) {
138 Ancestors.push_back(Hash);
142 for (llvm::hash_code Hash : llvm::reverse(Ancestors)) {
145 Cache.try_emplace(Hash, Cost);
147 dlog(
"distance({0} = {1})",
Path, Cost);
154 return R.first->getSecond();
157 R.first->second = forScheme(U->scheme()).
distance(U->body());
159 log(
"URIDistance::distance() of unparseable {0}: {1}",
URI, U.takeError());
161 return R.first->second;
164FileDistance &URIDistance::forScheme(llvm::StringRef Scheme) {
165 auto &Delegate = ByScheme[Scheme];
167 llvm::StringMap<SourceParams> SchemeSources;
168 for (
const auto &Source : Sources) {
170 SchemeSources.try_emplace(U->body(), Source.getValue());
172 llvm::consumeError(U.takeError());
174 dlog(
"FileDistance for scheme {0}: {1}/{2} sources", Scheme,
175 SchemeSources.size(), Sources.size());
176 Delegate.reset(
new FileDistance(std::move(SchemeSources), Opts));
181static std::pair<std::string, int>
scopeToPath(llvm::StringRef Scope) {
182 llvm::SmallVector<llvm::StringRef> Split;
183 Scope.split(Split,
"::", -1,
false);
184 return {
"/" + llvm::join(Split,
"/"), Split.size()};
192 Opts.AllowDownTraversalFromRoot =
false;
194 llvm::StringMap<SourceParams> Sources;
195 llvm::StringRef Preferred =
203 Param.
Cost = S ==
"" ? 4 : 0;
204 else if (Preferred.starts_with(S) && !S.empty())
207 Param.
Cost = S ==
"" ? 6 : 2;
211 Sources[
Path.first] = std::move(Param);
std::vector< std::string > QueryScopes
static constexpr unsigned Unreachable
FileDistance(llvm::StringMap< SourceParams > Sources, const FileDistanceOptions &Opts={})
unsigned distance(llvm::StringRef Path)
static const llvm::hash_code RootHash
unsigned distance(llvm::StringRef SymbolScope)
ScopeDistance(llvm::ArrayRef< std::string > QueryScopes)
QueryScopes[0] is the preferred scope.
unsigned distance(llvm::StringRef URI)
A URI describes the location of a source file.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
llvm::StringRef body() const
Returns decoded body e.g. "/D41946".
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
static FileDistance createScopeFileDistance(llvm::ArrayRef< std::string > QueryScopes)
std::string Path
A typedef to represent a file path.
void log(const char *Fmt, Ts &&... Vals)
static llvm::SmallString< 128 > canonicalize(llvm::StringRef Path)
static std::pair< std::string, int > scopeToPath(llvm::StringRef Scope)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
bool AllowDownTraversalFromRoot