10 #include "llvm/ADT/StringExtras.h" 11 #include "llvm/ADT/Twine.h" 12 #include "llvm/Support/Error.h" 13 #include "llvm/Support/Format.h" 14 #include "llvm/Support/FormatVariadic.h" 15 #include "llvm/Support/Path.h" 25 return llvm::make_error<llvm::StringError>(
Message,
26 llvm::inconvertibleErrorCode());
33 class FileSystemScheme :
public URIScheme {
35 llvm::Expected<std::string>
36 getAbsolutePath(llvm::StringRef , llvm::StringRef Body,
37 llvm::StringRef )
const override {
38 if (!Body.startswith(
"/"))
39 return make_string_error(
"File scheme: expect body to be an absolute " 40 "path starting with '/': " +
43 if (Body.size() > 2 && Body[0] ==
'/' && Body[2] ==
':')
44 Body.consume_front(
"/");
45 llvm::SmallVector<char, 16>
Path(Body.begin(), Body.end());
46 llvm::sys::path::native(
Path);
47 return std::string(
Path.begin(),
Path.end());
51 uriFromAbsolutePath(llvm::StringRef AbsolutePath)
const override {
54 if (AbsolutePath.size() > 1 && AbsolutePath[1] ==
':')
56 Body += llvm::sys::path::convert_to_slash(AbsolutePath);
57 return URI(
"file",
"", Body);
61 llvm::Expected<std::unique_ptr<URIScheme>>
62 findSchemeByName(llvm::StringRef Scheme) {
64 return std::make_unique<FileSystemScheme>();
66 for (
auto I = URISchemeRegistry::begin(),
E = URISchemeRegistry::end();
68 if (I->getName() != Scheme)
70 return I->instantiate();
72 return make_string_error(
"Can't find scheme: " + Scheme);
75 bool shouldEscape(
unsigned char C) {
77 if ((C >=
'a' && C <=
'z') || (C >=
'A' && C <=
'Z') ||
78 (C >=
'0' && C <=
'9'))
97 void percentEncode(llvm::StringRef Content, std::string &Out) {
99 for (
unsigned char C : Content)
103 Out.push_back(llvm::hexdigit(C / 16));
104 Out.push_back(llvm::hexdigit(C % 16));
106 { Out.push_back(C); }
110 std::string percentDecode(llvm::StringRef Content) {
112 for (
auto I = Content.begin(),
E = Content.end(); I !=
E; ++I) {
117 if (*I ==
'%' && I + 2 < Content.end() && llvm::isHexDigit(*(I + 1)) &&
118 llvm::isHexDigit(*(I + 2))) {
119 Result.push_back(llvm::hexFromNibbles(*(I + 1), *(I + 2)));
122 Result.push_back(*I);
127 bool isValidScheme(llvm::StringRef Scheme) {
130 if (!llvm::isAlpha(Scheme[0]))
132 return std::all_of(Scheme.begin() + 1, Scheme.end(), [](
char C) {
133 return llvm::isAlnum(C) || C ==
'+' || C ==
'.' || C ==
'-';
139 URI::URI(llvm::StringRef Scheme, llvm::StringRef Authority,
140 llvm::StringRef Body)
141 : Scheme(Scheme), Authority(Authority), Body(Body) {
142 assert(!Scheme.empty());
143 assert((Authority.empty() || Body.startswith(
"/")) &&
144 "URI body must start with '/' when authority is present.");
149 percentEncode(Scheme, Result);
150 Result.push_back(
':');
151 if (Authority.empty() && Body.empty())
155 if (!Authority.empty() || llvm::StringRef(Body).startswith(
"/"))
158 percentEncode(Authority, Result);
160 percentEncode(Body, Result);
166 llvm::StringRef Uri = OrigUri;
168 auto Pos = Uri.find(
':');
169 if (
Pos == llvm::StringRef::npos)
170 return make_string_error(
"Scheme must be provided in URI: " + OrigUri);
171 auto SchemeStr = Uri.substr(0,
Pos);
172 U.Scheme = percentDecode(SchemeStr);
173 if (!isValidScheme(U.Scheme))
174 return make_string_error(llvm::formatv(
"Invalid scheme: {0} (decoded: {1})",
175 SchemeStr, U.Scheme));
176 Uri = Uri.substr(
Pos + 1);
177 if (Uri.consume_front(
"//")) {
179 U.Authority = percentDecode(Uri.substr(0,
Pos));
180 Uri = Uri.substr(
Pos);
182 U.Body = percentDecode(Uri);
187 llvm::StringRef HintPath) {
190 return Uri.takeError();
193 return Path.takeError();
198 llvm::StringRef Scheme) {
199 if (!llvm::sys::path::is_absolute(AbsolutePath))
200 return make_string_error(
"Not a valid absolute path: " + AbsolutePath);
201 auto S = findSchemeByName(Scheme);
203 return S.takeError();
204 return S->get()->uriFromAbsolutePath(AbsolutePath);
208 if (!llvm::sys::path::is_absolute(AbsolutePath))
210 (
"Not a valid absolute path: " + AbsolutePath).str().c_str());
211 for (
auto &
Entry : URISchemeRegistry::entries()) {
212 auto URI =
Entry.instantiate()->uriFromAbsolutePath(AbsolutePath);
217 llvm::consumeError(
URI.takeError());
220 return std::move(*
URI);
227 auto U = FileSystemScheme().uriFromAbsolutePath(AbsolutePath);
230 return std::move(*U);
234 llvm::StringRef HintPath) {
235 auto S = findSchemeByName(Uri.Scheme);
237 return S.takeError();
238 return S->get()->getAbsolutePath(Uri.Authority, Uri.Body, HintPath);
242 llvm::StringRef HintPath) {
243 if (!llvm::sys::path::is_absolute(AbsPath))
244 llvm_unreachable((
"Not a valid absolute path: " + AbsPath).str().c_str());
245 for (
auto &
Entry : URISchemeRegistry::entries()) {
246 auto S =
Entry.instantiate();
247 auto U = S->uriFromAbsolutePath(AbsPath);
252 llvm::consumeError(U.takeError());
255 return S->getAbsolutePath(U->Authority, U->Body, HintPath);
262 auto S = findSchemeByName(Uri.Scheme);
264 return S.takeError();
265 return S->get()->getIncludeSpelling(Uri);
constexpr llvm::StringLiteral Message
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
static URI createFile(llvm::StringRef AbsolutePath)
This creates a file:// URI for AbsolutePath. The path must be absolute.
llvm::Registry< URIScheme > URISchemeRegistry
By default, a "file" scheme is supported where URI paths are always absolute in the file system...
static llvm::Expected< std::string > resolvePath(llvm::StringRef AbsPath, llvm::StringRef HintPath="")
Resolves AbsPath into a canonical path of its URI, by converting AbsPath to URI and resolving the URI...
std::string Path
A typedef to represent a file path.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
A URI describes the location of a source file.
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
static llvm::Expected< std::string > includeSpelling(const URI &U)
Gets the preferred spelling of this file for #include, if there is one, e.g.
static llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
std::string toString() const
Returns a string URI with all components percent-encoded.