hokein created this revision. hokein added a reviewer: sammccall. Herald added subscribers: MaskRay, ioeric, jkorous-apple, ilya-biryukov, klimek.
Calculating the include path from absolute file path does not always work for all build system, e.g. bazel uses symlink as the build working directory. The absolute file path from editor and clang is diverged from each other. We need to address it properly in build sysmtem integration. This patch worksarounds the issue by providing a hook in URI which allows clients to provide their customized include path. Repository: rCTE Clang Tools Extra https://reviews.llvm.org/D45426 Files: clangd/ClangdServer.cpp clangd/URI.cpp clangd/URI.h unittests/clangd/ClangdTests.cpp unittests/clangd/TestScheme.h unittests/clangd/URITests.cpp Index: unittests/clangd/URITests.cpp =================================================================== --- unittests/clangd/URITests.cpp +++ unittests/clangd/URITests.cpp @@ -47,6 +47,10 @@ return URI(Scheme, /*Authority=*/"", AbsolutePath.substr(Pos + llvm::StringRef(TestRoot).size())); } + + llvm::Expected<std::string> getIncludePath(const URI &U) const override { + return ("\"" + U.body() + "\"").str(); + } }; const char *TestScheme::Scheme = "unittest"; Index: unittests/clangd/ClangdTests.cpp =================================================================== --- unittests/clangd/ClangdTests.cpp +++ unittests/clangd/ClangdTests.cpp @@ -961,6 +961,10 @@ /*Preferred=*/"<Y.h>", "<Y.h>")); EXPECT_TRUE(Inserted(OriginalHeader, PreferredHeader, "\"Y.h\"")); EXPECT_TRUE(Inserted("<y.h>", PreferredHeader, "\"Y.h\"")); + auto TestURIHeader = URI::create("/abc/test-root/x/y/z.h", "unittest"); + EXPECT_TRUE(static_cast<bool>(TestURIHeader)); + EXPECT_TRUE(Inserted(TestURIHeader->toString(), "", "\"x/y/z.h\"")); + // Check that includes are sorted. const auto Expected = R"cpp( Index: clangd/URI.h =================================================================== --- clangd/URI.h +++ clangd/URI.h @@ -60,6 +60,14 @@ static llvm::Expected<std::string> resolve(const URI &U, llvm::StringRef HintPath = ""); + /// Tries to get the include path of the file corresponding to the URI. + /// This allows clients to provide their customized include paths. + /// + /// If the returned string is non-empty, clangd will use it directly when + /// doing include insertion; otherwise we will fall back to the clang to + /// calculate the include path from the resolved absolute path. + static llvm::Expected<std::string> includePath(const URI &U); + friend bool operator==(const URI &LHS, const URI &RHS) { return std::tie(LHS.Scheme, LHS.Authority, LHS.Body) == std::tie(RHS.Scheme, RHS.Authority, RHS.Body); @@ -94,6 +102,13 @@ virtual llvm::Expected<URI> uriFromAbsolutePath(llvm::StringRef AbsolutePath) const = 0; + + /// Returns the include path of the file corresponding to the URI, which can + /// be #include directly. See URI::resolveIncludePath for details. + virtual llvm::Expected<std::string> + getIncludePath(const URI& U) const { + return ""; // no customized include path for this scheme. + } }; /// By default, a "file" scheme is supported where URI paths are always absolute Index: clangd/URI.cpp =================================================================== --- clangd/URI.cpp +++ clangd/URI.cpp @@ -196,5 +196,12 @@ return S->get()->getAbsolutePath(Uri.Authority, Uri.Body, HintPath); } +llvm::Expected<std::string> URI::includePath(const URI &Uri) { + auto S = findSchemeByName(Uri.Scheme); + if (!S) + return S.takeError(); + return S->get()->getIncludePath(Uri); +} + } // namespace clangd } // namespace clang Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -286,6 +286,13 @@ auto U = URI::parse(Header); if (!U) return U.takeError(); + + auto IncludePath = URI::includePath(*U); + if (!IncludePath) + return IncludePath.takeError(); + if (!IncludePath->empty()) + return HeaderFile{std::move(*IncludePath), /*Verbatim=*/true}; + auto Resolved = URI::resolve(*U, HintPath); if (!Resolved) return Resolved.takeError();
Index: unittests/clangd/URITests.cpp =================================================================== --- unittests/clangd/URITests.cpp +++ unittests/clangd/URITests.cpp @@ -47,6 +47,10 @@ return URI(Scheme, /*Authority=*/"", AbsolutePath.substr(Pos + llvm::StringRef(TestRoot).size())); } + + llvm::Expected<std::string> getIncludePath(const URI &U) const override { + return ("\"" + U.body() + "\"").str(); + } }; const char *TestScheme::Scheme = "unittest"; Index: unittests/clangd/ClangdTests.cpp =================================================================== --- unittests/clangd/ClangdTests.cpp +++ unittests/clangd/ClangdTests.cpp @@ -961,6 +961,10 @@ /*Preferred=*/"<Y.h>", "<Y.h>")); EXPECT_TRUE(Inserted(OriginalHeader, PreferredHeader, "\"Y.h\"")); EXPECT_TRUE(Inserted("<y.h>", PreferredHeader, "\"Y.h\"")); + auto TestURIHeader = URI::create("/abc/test-root/x/y/z.h", "unittest"); + EXPECT_TRUE(static_cast<bool>(TestURIHeader)); + EXPECT_TRUE(Inserted(TestURIHeader->toString(), "", "\"x/y/z.h\"")); + // Check that includes are sorted. const auto Expected = R"cpp( Index: clangd/URI.h =================================================================== --- clangd/URI.h +++ clangd/URI.h @@ -60,6 +60,14 @@ static llvm::Expected<std::string> resolve(const URI &U, llvm::StringRef HintPath = ""); + /// Tries to get the include path of the file corresponding to the URI. + /// This allows clients to provide their customized include paths. + /// + /// If the returned string is non-empty, clangd will use it directly when + /// doing include insertion; otherwise we will fall back to the clang to + /// calculate the include path from the resolved absolute path. + static llvm::Expected<std::string> includePath(const URI &U); + friend bool operator==(const URI &LHS, const URI &RHS) { return std::tie(LHS.Scheme, LHS.Authority, LHS.Body) == std::tie(RHS.Scheme, RHS.Authority, RHS.Body); @@ -94,6 +102,13 @@ virtual llvm::Expected<URI> uriFromAbsolutePath(llvm::StringRef AbsolutePath) const = 0; + + /// Returns the include path of the file corresponding to the URI, which can + /// be #include directly. See URI::resolveIncludePath for details. + virtual llvm::Expected<std::string> + getIncludePath(const URI& U) const { + return ""; // no customized include path for this scheme. + } }; /// By default, a "file" scheme is supported where URI paths are always absolute Index: clangd/URI.cpp =================================================================== --- clangd/URI.cpp +++ clangd/URI.cpp @@ -196,5 +196,12 @@ return S->get()->getAbsolutePath(Uri.Authority, Uri.Body, HintPath); } +llvm::Expected<std::string> URI::includePath(const URI &Uri) { + auto S = findSchemeByName(Uri.Scheme); + if (!S) + return S.takeError(); + return S->get()->getIncludePath(Uri); +} + } // namespace clangd } // namespace clang Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -286,6 +286,13 @@ auto U = URI::parse(Header); if (!U) return U.takeError(); + + auto IncludePath = URI::includePath(*U); + if (!IncludePath) + return IncludePath.takeError(); + if (!IncludePath->empty()) + return HeaderFile{std::move(*IncludePath), /*Verbatim=*/true}; + auto Resolved = URI::resolve(*U, HintPath); if (!Resolved) return Resolved.takeError();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits