comparison clang-tools-extra/clangd/URI.cpp @ 221:79ff65ed7e25

LLVM12 Original
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Tue, 15 Jun 2021 19:15:29 +0900
parents 1d019706d866
children c4bab56944e8
comparison
equal deleted inserted replaced
220:42394fc6a535 221:79ff65ed7e25
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 // 6 //
7 //===----------------------------------------------------------------------===// 7 //===----------------------------------------------------------------------===//
8 8
9 #include "URI.h" 9 #include "URI.h"
10 #include "support/Logger.h"
10 #include "llvm/ADT/StringExtras.h" 11 #include "llvm/ADT/StringExtras.h"
11 #include "llvm/ADT/Twine.h" 12 #include "llvm/ADT/Twine.h"
12 #include "llvm/Support/Error.h" 13 #include "llvm/Support/Error.h"
13 #include "llvm/Support/Format.h" 14 #include "llvm/Support/Format.h"
14 #include "llvm/Support/FormatVariadic.h" 15 #include "llvm/Support/FormatVariadic.h"
19 20
20 namespace clang { 21 namespace clang {
21 namespace clangd { 22 namespace clangd {
22 namespace { 23 namespace {
23 24
24 inline llvm::Error make_string_error(const llvm::Twine &Message) { 25 bool isWindowsPath(llvm::StringRef Path) {
25 return llvm::make_error<llvm::StringError>(Message, 26 return Path.size() > 1 && llvm::isAlpha(Path[0]) && Path[1] == ':';
26 llvm::inconvertibleErrorCode()); 27 }
28
29 bool isNetworkPath(llvm::StringRef Path) {
30 return Path.size() > 2 && Path[0] == Path[1] &&
31 llvm::sys::path::is_separator(Path[0]);
27 } 32 }
28 33
29 /// This manages file paths in the file system. All paths in the scheme 34 /// This manages file paths in the file system. All paths in the scheme
30 /// are absolute (with leading '/'). 35 /// are absolute (with leading '/').
31 /// Note that this scheme is hardcoded into the library and not registered in 36 /// Note that this scheme is hardcoded into the library and not registered in
32 /// registry. 37 /// registry.
33 class FileSystemScheme : public URIScheme { 38 class FileSystemScheme : public URIScheme {
34 public: 39 public:
35 llvm::Expected<std::string> 40 llvm::Expected<std::string>
36 getAbsolutePath(llvm::StringRef /*Authority*/, llvm::StringRef Body, 41 getAbsolutePath(llvm::StringRef Authority, llvm::StringRef Body,
37 llvm::StringRef /*HintPath*/) const override { 42 llvm::StringRef /*HintPath*/) const override {
38 if (!Body.startswith("/")) 43 if (!Body.startswith("/"))
39 return make_string_error("File scheme: expect body to be an absolute " 44 return error("File scheme: expect body to be an absolute path starting "
40 "path starting with '/': " + 45 "with '/': {0}",
41 Body); 46 Body);
42 // For Windows paths e.g. /X: 47 llvm::SmallString<128> Path;
43 if (Body.size() > 2 && Body[0] == '/' && Body[2] == ':') 48 if (!Authority.empty()) {
49 // Windows UNC paths e.g. file://server/share => \\server\share
50 ("//" + Authority).toVector(Path);
51 } else if (isWindowsPath(Body.substr(1))) {
52 // Windows paths e.g. file:///X:/path => X:\path
44 Body.consume_front("/"); 53 Body.consume_front("/");
45 llvm::SmallVector<char, 16> Path(Body.begin(), Body.end()); 54 }
55 Path.append(Body);
46 llvm::sys::path::native(Path); 56 llvm::sys::path::native(Path);
47 return std::string(Path.begin(), Path.end()); 57 return std::string(Path);
48 } 58 }
49 59
50 llvm::Expected<URI> 60 llvm::Expected<URI>
51 uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override { 61 uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override {
52 std::string Body; 62 std::string Body;
53 // For Windows paths e.g. X: 63 llvm::StringRef Authority;
54 if (AbsolutePath.size() > 1 && AbsolutePath[1] == ':') 64 llvm::StringRef Root = llvm::sys::path::root_name(AbsolutePath);
65 if (isNetworkPath(Root)) {
66 // Windows UNC paths e.g. \\server\share => file://server/share
67 Authority = Root.drop_front(2);
68 AbsolutePath.consume_front(Root);
69 } else if (isWindowsPath(Root)) {
70 // Windows paths e.g. X:\path => file:///X:/path
55 Body = "/"; 71 Body = "/";
72 }
56 Body += llvm::sys::path::convert_to_slash(AbsolutePath); 73 Body += llvm::sys::path::convert_to_slash(AbsolutePath);
57 return URI("file", /*Authority=*/"", Body); 74 return URI("file", Authority, Body);
58 } 75 }
59 }; 76 };
60 77
61 llvm::Expected<std::unique_ptr<URIScheme>> 78 llvm::Expected<std::unique_ptr<URIScheme>>
62 findSchemeByName(llvm::StringRef Scheme) { 79 findSchemeByName(llvm::StringRef Scheme) {
63 if (Scheme == "file") 80 if (Scheme == "file")
64 return std::make_unique<FileSystemScheme>(); 81 return std::make_unique<FileSystemScheme>();
65 82
66 for (auto I = URISchemeRegistry::begin(), E = URISchemeRegistry::end(); 83 for (const auto &URIScheme : URISchemeRegistry::entries()) {
67 I != E; ++I) { 84 if (URIScheme.getName() != Scheme)
68 if (I->getName() != Scheme) 85 continue;
69 continue; 86 return URIScheme.instantiate();
70 return I->instantiate(); 87 }
71 } 88 return error("Can't find scheme: {0}", Scheme);
72 return make_string_error("Can't find scheme: " + Scheme);
73 } 89 }
74 90
75 bool shouldEscape(unsigned char C) { 91 bool shouldEscape(unsigned char C) {
76 // Unreserved characters. 92 // Unreserved characters.
77 if ((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || 93 if ((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
93 /// Encodes a string according to percent-encoding. 109 /// Encodes a string according to percent-encoding.
94 /// - Unreserved characters are not escaped. 110 /// - Unreserved characters are not escaped.
95 /// - Reserved characters always escaped with exceptions like '/'. 111 /// - Reserved characters always escaped with exceptions like '/'.
96 /// - All other characters are escaped. 112 /// - All other characters are escaped.
97 void percentEncode(llvm::StringRef Content, std::string &Out) { 113 void percentEncode(llvm::StringRef Content, std::string &Out) {
98 std::string Result;
99 for (unsigned char C : Content) 114 for (unsigned char C : Content)
100 if (shouldEscape(C)) 115 if (shouldEscape(C)) {
101 {
102 Out.push_back('%'); 116 Out.push_back('%');
103 Out.push_back(llvm::hexdigit(C / 16)); 117 Out.push_back(llvm::hexdigit(C / 16));
104 Out.push_back(llvm::hexdigit(C % 16)); 118 Out.push_back(llvm::hexdigit(C % 16));
105 } else 119 } else {
106 { Out.push_back(C); } 120 Out.push_back(C);
121 }
107 } 122 }
108 123
109 /// Decodes a string according to percent-encoding. 124 /// Decodes a string according to percent-encoding.
110 std::string percentDecode(llvm::StringRef Content) { 125 std::string percentDecode(llvm::StringRef Content) {
111 std::string Result; 126 std::string Result;
165 URI U; 180 URI U;
166 llvm::StringRef Uri = OrigUri; 181 llvm::StringRef Uri = OrigUri;
167 182
168 auto Pos = Uri.find(':'); 183 auto Pos = Uri.find(':');
169 if (Pos == llvm::StringRef::npos) 184 if (Pos == llvm::StringRef::npos)
170 return make_string_error("Scheme must be provided in URI: " + OrigUri); 185 return error("Scheme must be provided in URI: {0}", OrigUri);
171 auto SchemeStr = Uri.substr(0, Pos); 186 auto SchemeStr = Uri.substr(0, Pos);
172 U.Scheme = percentDecode(SchemeStr); 187 U.Scheme = percentDecode(SchemeStr);
173 if (!isValidScheme(U.Scheme)) 188 if (!isValidScheme(U.Scheme))
174 return make_string_error(llvm::formatv("Invalid scheme: {0} (decoded: {1})", 189 return error("Invalid scheme: {0} (decoded: {1})", SchemeStr, U.Scheme);
175 SchemeStr, U.Scheme));
176 Uri = Uri.substr(Pos + 1); 190 Uri = Uri.substr(Pos + 1);
177 if (Uri.consume_front("//")) { 191 if (Uri.consume_front("//")) {
178 Pos = Uri.find('/'); 192 Pos = Uri.find('/');
179 U.Authority = percentDecode(Uri.substr(0, Pos)); 193 U.Authority = percentDecode(Uri.substr(0, Pos));
180 Uri = Uri.substr(Pos); 194 Uri = Uri.substr(Pos);
195 } 209 }
196 210
197 llvm::Expected<URI> URI::create(llvm::StringRef AbsolutePath, 211 llvm::Expected<URI> URI::create(llvm::StringRef AbsolutePath,
198 llvm::StringRef Scheme) { 212 llvm::StringRef Scheme) {
199 if (!llvm::sys::path::is_absolute(AbsolutePath)) 213 if (!llvm::sys::path::is_absolute(AbsolutePath))
200 return make_string_error("Not a valid absolute path: " + AbsolutePath); 214 return error("Not a valid absolute path: {0}", AbsolutePath);
201 auto S = findSchemeByName(Scheme); 215 auto S = findSchemeByName(Scheme);
202 if (!S) 216 if (!S)
203 return S.takeError(); 217 return S.takeError();
204 return S->get()->uriFromAbsolutePath(AbsolutePath); 218 return S->get()->uriFromAbsolutePath(AbsolutePath);
205 } 219 }