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 @@ -279,6 +279,10 @@ void symbolInfo(PathRef File, Position Pos, Callback> CB); + /// Get semantic ranges around a specified position in a file. + void semanticRanges(PathRef File, Position Pos, + Callback> CB); + /// Returns estimated memory usage for each of the currently open files. /// The order of results is unspecified. /// Overall memory usage of clangd may be significantly more than reported 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 @@ -17,6 +17,7 @@ #include "Preamble.h" #include "Protocol.h" #include "SemanticHighlighting.h" +#include "SemanticSelection.h" #include "SourceCode.h" #include "TUScheduler.h" #include "Trace.h" @@ -125,8 +126,8 @@ // critical paths. WorkScheduler( CDB, Opts.AsyncThreadsCount, Opts.StorePreamblesInMemory, - std::make_unique( - DynamicIdx.get(), DiagConsumer, Opts.SemanticHighlighting), + std::make_unique(DynamicIdx.get(), DiagConsumer, + Opts.SemanticHighlighting), Opts.UpdateDebounce, Opts.RetentionPolicy) { // Adds an index to the stack, at higher priority than existing indexes. auto AddIndex = [&](SymbolIndex *Idx) { @@ -620,6 +621,17 @@ WorkScheduler.runWithAST("SymbolInfo", File, std::move(Action)); } +void ClangdServer::semanticRanges(PathRef File, Position Pos, + Callback> CB) { + auto Action = + [Pos, CB = std::move(CB)](llvm::Expected InpAST) mutable { + if (!InpAST) + return CB(InpAST.takeError()); + CB(clangd::getSemanticRanges(InpAST->AST, Pos)); + }; + WorkScheduler.runWithAST("SemanticRanges", File, std::move(Action)); +} + std::vector> ClangdServer::getUsedBytesPerFile() const { return WorkScheduler.getUsedBytesPerFile(); diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp @@ -7,10 +7,13 @@ //===----------------------------------------------------------------------===// #include "Annotations.h" +#include "ClangdServer.h" #include "Matchers.h" #include "Protocol.h" #include "SemanticSelection.h" #include "SourceCode.h" +#include "SyncAPI.h" +#include "TestFS.h" #include "TestTU.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -23,6 +26,11 @@ namespace { using ::testing::ElementsAreArray; +class IgnoreDiagnostics : public DiagnosticsConsumer { + void onDiagnosticsReady(PathRef File, + std::vector Diagnostics) override {} +}; + TEST(SemanticSelection, All) { const char *Tests[] = { R"cpp( // Single statement in a function body. @@ -138,6 +146,39 @@ << Test; } } + +TEST(SemanticSelection, RunViaClangDServer) { + MockFSProvider FS; + IgnoreDiagnostics DiagConsumer; + MockCompilationDatabase CDB; + ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest()); + + auto FooH = testPath("foo.h"); + const char *HeaderContents = R"cpp( + int foo(int x); + #define HASH(x) ((x) % 10) + )cpp"; + Annotations HeaderAnnotations(HeaderContents); + FS.Files[FooH] = HeaderAnnotations.code(); + Server.addDocument(FooH, HeaderAnnotations.code()); + + auto FooCpp = testPath("Foo.cpp"); + const char *SourceContents = R"cpp( + #include "foo.h" + [[void bar(int& inp) [[{ + // inp = HASH(foo(inp)); + [[inp = [[HASH([[foo([[in^p]])]])]]]]; + }]]]] + )cpp"; + Annotations SourceAnnotations(SourceContents); + FS.Files[FooCpp] = SourceAnnotations.code(); + Server.addDocument(FooCpp, SourceAnnotations.code()); + + auto Ranges = runSemanticRanges(Server, FooCpp, SourceAnnotations.point()); + ASSERT_TRUE(bool(Ranges)) + << "getSemanticRange returned an error: " << Ranges.takeError(); + EXPECT_THAT(*Ranges, ElementsAreArray(SourceAnnotations.ranges())); +} } // 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 @@ -53,6 +53,9 @@ SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req); RefSlab getRefs(const SymbolIndex &Index, SymbolID ID); +llvm::Expected> +runSemanticRanges(ClangdServer &Server, PathRef File, Position Pos); + } // 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 @@ -145,5 +145,12 @@ return std::move(Slab).build(); } +llvm::Expected> +runSemanticRanges(ClangdServer &Server, PathRef File, Position Pos) { + llvm::Optional>> Result; + Server.semanticRanges(File, Pos, capture(Result)); + return std::move(*Result); +} + } // namespace clangd } // namespace clang