diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1038,10 +1038,16 @@ void ClangdLSPServer::onSwitchSourceHeader( const TextDocumentIdentifier &Params, Callback> Reply) { - if (auto Result = Server->switchSourceHeader(Params.uri.file())) - Reply(URIForFile::canonicalize(*Result, Params.uri.file())); - else - Reply(llvm::None); + Server->switchSourceHeader( + Params.uri.file(), + [Reply = std::move(Reply), + Params](llvm::Expected> Path) mutable { + if (!Path) + return Reply(Path.takeError()); + if (*Path) + Reply(URIForFile::canonicalize(**Path, Params.uri.file())); + return Reply(llvm::None); + }); } void ClangdLSPServer::onDocumentHighlight( diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -194,7 +194,8 @@ /// Helper function that returns a path to the corresponding source file when /// given a header file and vice versa. - llvm::Optional switchSourceHeader(PathRef Path); + void switchSourceHeader(PathRef Path, + Callback> CB); /// Get document highlights for a given position. void findDocumentHighlights(PathRef File, Position Pos, diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -449,8 +449,18 @@ WorkScheduler.runWithAST("Definitions", File, std::move(Action)); } -llvm::Optional ClangdServer::switchSourceHeader(PathRef Path) { - return getCorrespondingHeaderOrSource(Path, FSProvider.getFileSystem()); +void ClangdServer::switchSourceHeader( + PathRef Path, Callback> CB) { + if (auto CorrespondingFile = + getCorrespondingHeaderOrSource(Path, FSProvider.getFileSystem())) + return CB(std::move(CorrespondingFile)); + auto Action = [Path, CB = std::move(CB), + this](llvm::Expected InpAST) mutable { + if (!InpAST) + return CB(InpAST.takeError()); + CB(getCorrespondingHeaderOrSource(Path, InpAST->AST, Index)); + }; + WorkScheduler.runWithAST("SwitchHeaderSource", Path, std::move(Action)); } llvm::Expected diff --git a/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp b/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp --- a/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp +++ b/clang-tools-extra/clangd/unittests/HeaderSourceSwitchTests.cpp @@ -8,6 +8,7 @@ #include "HeaderSourceSwitch.h" +#include "SyncAPI.h" #include "TestFS.h" #include "TestTU.h" #include "index/MemIndex.h" @@ -240,6 +241,31 @@ } } +TEST(HeaderSourceSwitchTest, ClangdServerIntegration) { + class IgnoreDiagnostics : public DiagnosticsConsumer { + void onDiagnosticsReady(PathRef File, + std::vector Diagnostics) override {} + } DiagConsumer; + MockCompilationDatabase CDB; + CDB.ExtraClangFlags = {"-I../include"}; // add search directory. + MockFSProvider FS; + // File heuristic fails here, we rely on the index to find the .h file. + std::string CppPath = testPath("src/lib/test.cpp"); + std::string HeaderPath = testPath("src/include/test.h"); + FS.Files[HeaderPath] = "void foo();"; + const std::string FileContent = R"cpp( + #include "test.h" + void foo() {}; + )cpp"; + FS.Files[CppPath] = FileContent; + auto Options = ClangdServer::optsForTest(); + Options.BuildDynamicSymbolIndex = true; + ClangdServer Server(CDB, FS, DiagConsumer, Options); + runAddDocument(Server, CppPath, FileContent); + EXPECT_EQ(HeaderPath, + *llvm::cantFail(runSwitchHeaderSource(Server, CppPath))); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.h b/clang-tools-extra/clangd/unittests/SyncAPI.h --- a/clang-tools-extra/clangd/unittests/SyncAPI.h +++ b/clang-tools-extra/clangd/unittests/SyncAPI.h @@ -56,6 +56,9 @@ llvm::Expected> runSemanticRanges(ClangdServer &Server, PathRef File, Position Pos); +llvm::Expected> +runSwitchHeaderSource(ClangdServer &Server, PathRef File); + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.cpp b/clang-tools-extra/clangd/unittests/SyncAPI.cpp --- a/clang-tools-extra/clangd/unittests/SyncAPI.cpp +++ b/clang-tools-extra/clangd/unittests/SyncAPI.cpp @@ -152,5 +152,12 @@ return std::move(*Result); } +llvm::Expected> +runSwitchHeaderSource(ClangdServer &Server, PathRef File) { + llvm::Optional>> Result; + Server.switchSourceHeader(File, capture(Result)); + return std::move(*Result); +} + } // namespace clangd } // namespace clang