diff --git a/clang-tools-extra/clangd/URI.h b/clang-tools-extra/clangd/URI.h --- a/clang-tools-extra/clangd/URI.h +++ b/clang-tools-extra/clangd/URI.h @@ -31,7 +31,7 @@ /// Returns decoded scheme e.g. "https" llvm::StringRef scheme() const { return Scheme; } - /// Returns decoded authority e.g. "reviews.lvm.org" + /// Returns decoded authority e.g. "reviews.llvm.org" llvm::StringRef authority() const { return Authority; } /// Returns decoded body e.g. "/D41946" llvm::StringRef body() const { return Body; } diff --git a/clang-tools-extra/clangd/URI.cpp b/clang-tools-extra/clangd/URI.cpp --- a/clang-tools-extra/clangd/URI.cpp +++ b/clang-tools-extra/clangd/URI.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "URI.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" @@ -58,6 +60,55 @@ } }; +// FIXME(kirillbobyrev): Repo scheme requires two parameters: repository +// identifier (e.g. address; can be omitted in case there would be only one +// repository scheme used at a time which is probably true for the first +// iteration) and path to the project root. llvm::Registry which is used to +// store all known schemas does not support constructors with parameters. Hence, +// right now the prototype implementation contains hard-coded static parameters +// that should be actually passed to the constructor. Doing this properly +// requires modifications to the URISchemeRegistry pattern usage. +class RepoScheme : public URIScheme { +public: + // Authority points to the repository address, should be same as + // Repository. + // HintPath points to the repository root in filesystem, should be same as + // Root. + llvm::Expected + getAbsolutePath(llvm::StringRef Authority, llvm::StringRef Body, + llvm::StringRef HintPath) const override { + if (Authority != Repository) + return make_string_error( + "Unable to resolve URI because authorities do not match: given " + + Authority + "have " + Repository); + if (HintPath != Root) + return make_string_error( + "Unable to resolve repository URI with given root " + HintPath + + " different from " + Root); + llvm::SmallString<20> AbsolutePath = llvm::StringRef(Root); + llvm::sys::path::append(AbsolutePath, Body); + return AbsolutePath.str().str(); + } + + llvm::Expected + uriFromAbsolutePath(llvm::StringRef AbsolutePath) const override { + llvm::SmallString<12> Body = AbsolutePath; + // Strip Root from AbsolutePath. + if (!llvm::sys::path::replace_path_prefix(Body, Root, "")) + return make_string_error("Unable to create URI " + AbsolutePath + + " outside the repository " + Root); + return URI("repo", Repository, Body.str()); + } + + static const std::string Repository; + static const std::string Root; +}; + +const std::string RepoScheme::Repository = "remoteindex.com"; +const std::string RepoScheme::Root = "/home/username/dev/src/llvm-project"; + +static URISchemeRegistry::Add X("repo", "Remote indexing service"); + llvm::Expected> findSchemeByName(llvm::StringRef Scheme) { if (Scheme == "file") @@ -96,13 +147,13 @@ void percentEncode(llvm::StringRef Content, std::string &Out) { std::string Result; for (unsigned char C : Content) - if (shouldEscape(C)) - { + if (shouldEscape(C)) { Out.push_back('%'); Out.push_back(llvm::hexdigit(C / 16)); Out.push_back(llvm::hexdigit(C % 16)); - } else - { Out.push_back(C); } + } else { + Out.push_back(C); + } } /// Decodes a string according to percent-encoding. @@ -151,8 +202,7 @@ return Result; // If authority if empty, we only print body if it starts with "/"; otherwise, // the URI is invalid. - if (!Authority.empty() || llvm::StringRef(Body).startswith("/")) - { + if (!Authority.empty() || llvm::StringRef(Body).startswith("/")) { Result.append("//"); percentEncode(Authority, Result); } diff --git a/clang-tools-extra/clangd/unittests/URITests.cpp b/clang-tools-extra/clangd/unittests/URITests.cpp --- a/clang-tools-extra/clangd/unittests/URITests.cpp +++ b/clang-tools-extra/clangd/unittests/URITests.cpp @@ -182,6 +182,16 @@ EXPECT_TRUE(FailedResolve("file:a/b/c")); } +TEST(URITest, RepoScheme) { + EXPECT_THAT(createOrDie("/home/username/dev/src/llvm-project/a/b/c", "repo"), + "repo://remoteindex.com/a/b/c"); + EXPECT_EQ(parseOrDie("repo://remoteindex.com/llvm/a/b/c").body(), + "/llvm/a/b/c"); + EXPECT_EQ(parseOrDie("repo://remoteindex.com/llvm/a/b/c").authority(), + "remoteindex.com"); + EXPECT_EQ(parseOrDie("repo://remoteindex.com/llvm/a/b/c").scheme(), "repo"); +} + } // namespace } // namespace clangd } // namespace clang