11 #include "llvm/ADT/StringExtras.h" 12 #include "llvm/ADT/Twine.h" 13 #include "llvm/Support/Error.h" 14 #include "llvm/Support/Format.h" 15 #include "llvm/Support/FormatVariadic.h" 16 #include "llvm/Support/Path.h" 27 inline llvm::Error make_string_error(
const llvm::Twine &
Message) {
28 return llvm::make_error<llvm::StringError>(
Message,
29 llvm::inconvertibleErrorCode());
36 class FileSystemScheme :
public URIScheme {
38 llvm::Expected<std::string>
39 getAbsolutePath(llvm::StringRef , llvm::StringRef Body,
40 llvm::StringRef )
const override {
41 if (!Body.startswith(
"/"))
42 return make_string_error(
"File scheme: expect body to be an absolute " 43 "path starting with '/': " +
46 if (Body.size() > 2 && Body[0] ==
'/' && Body[2] ==
':')
47 Body.consume_front(
"/");
48 llvm::SmallVector<char, 16>
Path(Body.begin(), Body.end());
49 llvm::sys::path::native(
Path);
50 return std::string(
Path.begin(),
Path.end());
54 uriFromAbsolutePath(llvm::StringRef AbsolutePath)
const override {
57 if (AbsolutePath.size() > 1 && AbsolutePath[1] ==
':')
59 Body += llvm::sys::path::convert_to_slash(AbsolutePath);
60 return URI(
"file",
"", Body);
64 llvm::Expected<std::unique_ptr<URIScheme>>
65 findSchemeByName(llvm::StringRef Scheme) {
67 return llvm::make_unique<FileSystemScheme>();
69 for (
auto I = URISchemeRegistry::begin(), E = URISchemeRegistry::end();
71 if (I->getName() != Scheme)
73 return I->instantiate();
75 return make_string_error(
"Can't find scheme: " + Scheme);
78 bool shouldEscape(
unsigned char C) {
80 if ((C >=
'a' && C <=
'z') || (C >=
'A' && C <=
'Z') ||
81 (C >=
'0' && C <=
'9'))
100 std::string percentEncode(llvm::StringRef Content) {
102 llvm::raw_string_ostream OS(Result);
103 for (
unsigned char C : Content)
105 OS <<
'%' << llvm::format_hex_no_prefix(C, 2,
true);
114 std::string percentDecode(llvm::StringRef Content) {
116 for (
auto I = Content.begin(), E = Content.end(); I != E; ++I) {
121 if (*I ==
'%' && I + 2 < Content.end() && llvm::isHexDigit(*(I + 1)) &&
122 llvm::isHexDigit(*(I + 2))) {
123 Result.push_back(llvm::hexFromNibbles(*(I + 1), *(I + 2)));
126 Result.push_back(*I);
131 bool isValidScheme(llvm::StringRef Scheme) {
134 if (!llvm::isAlpha(Scheme[0]))
136 return std::all_of(Scheme.begin() + 1, Scheme.end(), [](
char C) {
137 return llvm::isAlnum(C) || C ==
'+' || C ==
'.' || C ==
'-';
143 URI::URI(llvm::StringRef Scheme, llvm::StringRef Authority,
144 llvm::StringRef Body)
145 : Scheme(Scheme), Authority(Authority), Body(Body) {
146 assert(!Scheme.empty());
147 assert((Authority.empty() || Body.startswith(
"/")) &&
148 "URI body must start with '/' when authority is present.");
153 llvm::raw_string_ostream OS(Result);
154 OS << percentEncode(Scheme) <<
":";
155 if (Authority.empty() && Body.empty())
159 if (!Authority.empty() || llvm::StringRef(Body).startswith(
"/"))
160 OS <<
"//" << percentEncode(Authority);
161 OS << percentEncode(Body);
168 llvm::StringRef Uri = OrigUri;
170 auto Pos = Uri.find(
':');
171 if (
Pos == llvm::StringRef::npos)
172 return make_string_error(
"Scheme must be provided in URI: " + OrigUri);
173 auto SchemeStr = Uri.substr(0,
Pos);
174 U.Scheme = percentDecode(SchemeStr);
175 if (!isValidScheme(U.Scheme))
176 return make_string_error(llvm::formatv(
"Invalid scheme: {0} (decoded: {1})",
177 SchemeStr, U.Scheme));
178 Uri = Uri.substr(
Pos + 1);
179 if (Uri.consume_front(
"//")) {
181 U.Authority = percentDecode(Uri.substr(0,
Pos));
182 Uri = Uri.substr(
Pos);
184 U.Body = percentDecode(Uri);
189 llvm::StringRef Scheme) {
190 if (!llvm::sys::path::is_absolute(AbsolutePath))
191 return make_string_error(
"Not a valid absolute path: " + AbsolutePath);
192 auto S = findSchemeByName(Scheme);
194 return S.takeError();
195 return S->get()->uriFromAbsolutePath(AbsolutePath);
199 if (!llvm::sys::path::is_absolute(AbsolutePath))
201 (
"Not a valid absolute path: " + AbsolutePath).str().c_str());
202 for (
auto &
Entry : URISchemeRegistry::entries()) {
203 auto URI =
Entry.instantiate()->uriFromAbsolutePath(AbsolutePath);
208 llvm::consumeError(
URI.takeError());
211 return std::move(*
URI);
218 auto U = FileSystemScheme().uriFromAbsolutePath(AbsolutePath);
221 return std::move(*U);
225 llvm::StringRef HintPath) {
226 auto S = findSchemeByName(Uri.Scheme);
228 return S.takeError();
229 return S->get()->getAbsolutePath(Uri.Authority, Uri.Body, HintPath);
233 llvm::StringRef HintPath) {
234 if (!llvm::sys::path::is_absolute(AbsPath))
235 llvm_unreachable((
"Not a valid absolute path: " + AbsPath).str().c_str());
236 for (
auto &
Entry : URISchemeRegistry::entries()) {
237 auto S =
Entry.instantiate();
238 auto U = S->uriFromAbsolutePath(AbsPath);
243 llvm::consumeError(U.takeError());
246 return S->getAbsolutePath(U->Authority, U->Body, HintPath);
253 auto S = findSchemeByName(Uri.Scheme);
255 return S.takeError();
256 return S->get()->getIncludeSpelling(Uri);
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
static const StringRef Message
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.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
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.