35 #include "llvm/ADT/STLExtras.h"
47 llvm::SmallString<128> Result =
Path.rtrim(
'/');
48 native(Result, llvm::sys::path::Style::posix);
49 if (Result.empty() || Result.front() !=
'/')
50 Result.insert(Result.begin(),
'/');
61 llvm::DenseMap<llvm::hash_code, llvm::SmallVector<llvm::hash_code, 4>>
65 for (
const auto &S : Sources) {
67 dlog(
"Source {0} = {1}, MaxUp = {2}", Canonical, S.second.Cost,
68 S.second.MaxUpTraversals);
70 llvm::StringRef Rest = Canonical;
72 for (
unsigned I = 0; !Rest.empty(); ++I) {
73 Rest = parent_path(Rest, llvm::sys::path::Style::posix);
75 auto &Down = DownEdges[NextHash];
76 if (!llvm::is_contained(Down, Hash))
79 if (I > S.getValue().MaxUpTraversals) {
80 if (Cache.find(Hash) != Cache.end())
83 unsigned Cost = S.getValue().Cost + I * Opts.UpCost;
84 auto R = Cache.try_emplace(Hash, Cost);
86 if (Cost < R.first->second) {
87 R.first->second = Cost;
99 std::queue<llvm::hash_code> Next;
102 while (!Next.empty()) {
103 auto Parent = Next.front();
105 auto ParentCost = Cache.lookup(
Parent);
106 for (
auto Child : DownEdges.lookup(
Parent)) {
109 Cache.try_emplace(Child,
Unreachable).first->getSecond();
110 if (ParentCost + Opts.DownCost < ChildCost)
111 ChildCost = ParentCost + Opts.DownCost;
121 llvm::SmallVector<llvm::hash_code, 16> Ancestors;
123 for (llvm::StringRef Rest = Canonical; !Rest.empty();
124 Rest = parent_path(Rest, llvm::sys::path::Style::posix)) {
126 if (Hash ==
RootHash && !Ancestors.empty() &&
131 auto It = Cache.find(Hash);
132 if (It != Cache.end()) {
136 Ancestors.push_back(Hash);
140 for (llvm::hash_code Hash : llvm::reverse(Ancestors)) {
143 Cache.try_emplace(Hash, Cost);
145 dlog(
"distance({0} = {1})",
Path, Cost);
152 return R.first->getSecond();
155 R.first->second = forScheme(U->scheme()).
distance(U->body());
157 log(
"URIDistance::distance() of unparseable {0}: {1}",
URI, U.takeError());
159 return R.first->second;
162 FileDistance &URIDistance::forScheme(llvm::StringRef Scheme) {
163 auto &Delegate = ByScheme[Scheme];
165 llvm::StringMap<SourceParams> SchemeSources;
166 for (
const auto &Source : Sources) {
168 SchemeSources.try_emplace(U->body(), Source.getValue());
170 llvm::consumeError(U.takeError());
172 dlog(
"FileDistance for scheme {0}: {1}/{2} sources", Scheme,
173 SchemeSources.size(), Sources.size());
174 Delegate.reset(
new FileDistance(std::move(SchemeSources), Opts));
179 static std::pair<std::string, int>
scopeToPath(llvm::StringRef Scope) {
180 llvm::SmallVector<llvm::StringRef, 4> Split;
181 Scope.split(Split,
"::", -1,
false);
182 return {
"/" +
llvm::join(Split,
"/"), Split.size()};
190 Opts.AllowDownTraversalFromRoot =
false;
192 llvm::StringMap<SourceParams> Sources;
193 llvm::StringRef Preferred =
194 QueryScopes.empty() ?
"" : QueryScopes.front().c_str();
195 for (llvm::StringRef S : QueryScopes) {
201 Param.
Cost = S ==
"" ? 4 : 0;
202 else if (Preferred.startswith(S) && !S.empty())
205 Param.
Cost = S ==
"" ? 6 : 2;
209 Sources[
Path.first] = std::move(Param);