Mercurial > hg > CbC > CbC_llvm
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 } |