malaperle updated this revision to Diff 139968.
malaperle marked 4 inline comments as done.
malaperle added a comment.
Split the patch so that this part only has the workspace/symbol part
and the index model will be updated separately.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D44882
Files:
clangd/CMakeLists.txt
clangd/ClangdLSPServer.cpp
clangd/ClangdLSPServer.h
clangd/ClangdServer.cpp
clangd/ClangdServer.h
clangd/FindSymbols.cpp
clangd/FindSymbols.h
clangd/Protocol.cpp
clangd/Protocol.h
clangd/ProtocolHandlers.cpp
clangd/ProtocolHandlers.h
clangd/SourceCode.cpp
clangd/SourceCode.h
clangd/XRefs.cpp
clangd/index/SymbolCollector.cpp
clangd/tool/ClangdMain.cpp
test/clangd/initialize-params-invalid.test
test/clangd/initialize-params.test
unittests/clangd/CMakeLists.txt
unittests/clangd/FindSymbolsTests.cpp
unittests/clangd/SyncAPI.cpp
unittests/clangd/SyncAPI.h
Index: unittests/clangd/SyncAPI.h
===================================================================
--- unittests/clangd/SyncAPI.h
+++ unittests/clangd/SyncAPI.h
@@ -41,6 +41,10 @@
std::string runDumpAST(ClangdServer &Server, PathRef File);
+llvm::Expected<std::vector<SymbolInformation>>
+runWorkspaceSymbols(ClangdServer &Server, StringRef Query,
+ const WorkspaceSymbolOptions &Opts);
+
} // namespace clangd
} // namespace clang
Index: unittests/clangd/SyncAPI.cpp
===================================================================
--- unittests/clangd/SyncAPI.cpp
+++ unittests/clangd/SyncAPI.cpp
@@ -110,5 +110,13 @@
return std::move(*Result);
}
+llvm::Expected<std::vector<SymbolInformation>>
+runWorkspaceSymbols(ClangdServer &Server, StringRef Query,
+ const WorkspaceSymbolOptions &Opts) {
+ llvm::Optional<llvm::Expected<std::vector<SymbolInformation>>> Result;
+ Server.workspaceSymbols(Query, Opts, capture(Result));
+ return std::move(*Result);
+}
+
} // namespace clangd
} // namespace clang
Index: unittests/clangd/FindSymbolsTests.cpp
===================================================================
--- /dev/null
+++ unittests/clangd/FindSymbolsTests.cpp
@@ -0,0 +1,380 @@
+//===-- FindSymbolsTests.cpp -------------------------*- C++ -*------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "Annotations.h"
+#include "ClangdServer.h"
+#include "FindSymbols.h"
+#include "SyncAPI.h"
+#include "TestFS.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+
+void PrintTo(const SymbolInformation &I, std::ostream *O) {
+ llvm::raw_os_ostream OS(*O);
+ OS << I.containerName << I.name << " - " << toJSON(I);
+}
+
+namespace {
+
+using ::testing::AllOf;
+using ::testing::AnyOf;
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::UnorderedElementsAre;
+
+class IgnoreDiagnostics : public DiagnosticsConsumer {
+ void onDiagnosticsReady(PathRef File,
+ std::vector<Diag> Diagnostics) override {}
+};
+
+// GMock helpers for matching SymbolInfos items.
+MATCHER_P(Named, Name, "") { return arg.name == Name; }
+MATCHER_P(InContainer, ContainerName, "") {
+ return arg.containerName == ContainerName;
+}
+MATCHER_P(WithKind, Kind, "") { return arg.kind == Kind; }
+
+class WorkspaceSymbolsTest : public ::testing::Test {
+protected:
+ std::unique_ptr<MockFSProvider> FSProvider;
+ std::unique_ptr<MockCompilationDatabase> CDB;
+ std::unique_ptr<IgnoreDiagnostics> DiagConsumer;
+ std::unique_ptr<ClangdServer> Server;
+ std::unique_ptr<WorkspaceSymbolOptions> Opts;
+
+ virtual void SetUp() override {
+ FSProvider = llvm::make_unique<MockFSProvider>();
+ CDB = llvm::make_unique<MockCompilationDatabase>();
+ DiagConsumer = llvm::make_unique<IgnoreDiagnostics>();
+ auto ServerOpts = ClangdServer::optsForTest();
+ ServerOpts.BuildDynamicSymbolIndex = true;
+ Server = llvm::make_unique<ClangdServer>(*CDB, *FSProvider, *DiagConsumer,
+ ServerOpts);
+ Opts = llvm::make_unique<WorkspaceSymbolOptions>();
+ }
+
+ std::vector<SymbolInformation> getSymbols(StringRef Query) {
+ EXPECT_TRUE(Server->blockUntilIdleForTest()) << "Waiting for preamble";
+ auto SymbolInfos = runWorkspaceSymbols(*Server, Query, *Opts);
+ EXPECT_TRUE(bool(SymbolInfos)) << "workspaceSymbols returned an error";
+ return *SymbolInfos;
+ }
+
+ void addFile(StringRef FileName, StringRef Contents) {
+ auto Path = testPath(FileName);
+ FSProvider->Files[Path] = Contents;
+ Server->addDocument(Path, Contents);
+ }
+};
+
+} // namespace
+
+TEST_F(WorkspaceSymbolsTest, NoMacro) {
+ addFile("foo.cpp", R"cpp(
+ #define MACRO X
+ )cpp");
+
+ // Macros are not in the index.
+ EXPECT_THAT(getSymbols("macro"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, NoLocals) {
+ addFile("foo.cpp", R"cpp(
+ void test() {
+ struct LocalClass {};
+ int local_var;
+ })cpp");
+ EXPECT_THAT(getSymbols("local_var"), IsEmpty());
+ EXPECT_THAT(getSymbols("LocalClass"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, NoParams) {
+ addFile("foo.cpp", R"cpp(
+ void test(int FirstParam, int SecondParam) {
+ })cpp");
+ EXPECT_THAT(getSymbols("FirstParam"), IsEmpty());
+ EXPECT_THAT(getSymbols("SecondParam"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, ClassWithMembers) {
+ addFile("foo.h", R"cpp(
+ struct ClassWithMembers {
+ int method();
+ protected:
+ int field;
+ private:
+ int private_field;
+ };)cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("method"), IsEmpty());
+ EXPECT_THAT(getSymbols("ClassWithMembers::method"), IsEmpty());
+ EXPECT_THAT(getSymbols("ClassWithMembers::met"), IsEmpty());
+ EXPECT_THAT(getSymbols("field"), IsEmpty());
+ EXPECT_THAT(getSymbols("ClassWithMembers::"), IsEmpty());
+ EXPECT_THAT(getSymbols("ClassWithMembers:"), IsEmpty());
+ EXPECT_THAT(getSymbols("ClassWithMembers"),
+ ElementsAre(AllOf(Named("ClassWithMembers"), InContainer(""))));
+}
+
+TEST_F(WorkspaceSymbolsTest, ClassInNamespaceWithMembers) {
+ addFile("foo.h", R"cpp(
+ namespace ns1 {
+ struct ClassWithMembers {
+ int method();
+ };
+ })cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("ns1::ClassWithMembers::method"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, Globals) {
+ addFile("foo.h", R"cpp(
+ int global_var;
+
+ int global_func();
+
+ struct GlobalClass {};)cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(
+ getSymbols("global"),
+ UnorderedElementsAre(AllOf(Named("GlobalClass"), InContainer("")),
+ AllOf(Named("global_func"), InContainer("")),
+ AllOf(Named("global_var"), InContainer(""))));
+}
+
+TEST_F(WorkspaceSymbolsTest, Unnamed) {
+ addFile("foo.h", R"cpp(
+ struct {
+ int InUnnamed;
+ } UnnamedStruct;)cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("UnnamedStruct"), ElementsAre(Named("UnnamedStruct")));
+ EXPECT_THAT(getSymbols("InUnnamed"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, InMainFile) {
+ addFile("foo.cpp", R"cpp(
+ int test() {
+ }
+ )cpp");
+ EXPECT_THAT(getSymbols("test"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, AnonymousNamespace) {
+ addFile("foo.h", R"cpp(
+ namespace {
+ void test() {}
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("test"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, MultiFile) {
+ addFile("foo.h", R"cpp(
+ int foo() {
+ }
+ )cpp");
+ addFile("foo2.h", R"cpp(
+ int foo2() {
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ #include "foo2.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("foo"),
+ UnorderedElementsAre(AllOf(Named("foo"), InContainer("")),
+ AllOf(Named("foo2"), InContainer(""))));
+}
+
+TEST_F(WorkspaceSymbolsTest, GlobalNamespaceQueries) {
+ addFile("foo.h", R"cpp(
+ int foo() {
+ }
+ class Foo {
+ int a;
+ };
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("::"),
+ UnorderedElementsAre(AllOf(Named("Foo"), InContainer("")),
+ AllOf(Named("foo"), InContainer(""))));
+ EXPECT_THAT(getSymbols(":"), IsEmpty());
+ EXPECT_THAT(getSymbols(""), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, WithLimit) {
+ addFile("foo.h", R"cpp(
+ int foo;
+ int foo2;
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("foo"),
+ ElementsAre(AllOf(Named("foo"), InContainer("")),
+ AllOf(Named("foo2"), InContainer(""))));
+
+ Opts->Limit = 1;
+ EXPECT_THAT(getSymbols("foo"),
+ ElementsAre(AnyOf((Named("foo"), InContainer("")),
+ AllOf(Named("foo2"), InContainer("")))));
+}
+
+TEST_F(WorkspaceSymbolsTest, Enums) {
+ addFile("foo.h", R"cpp(
+ enum {
+ Red
+ };
+ enum Color1 {
+ Green
+ };
+ enum class Color2 {
+ Yellow
+ };
+ namespace ns {
+ enum {
+ Black
+ };
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("Red"),
+ ElementsAre(AllOf(Named("Red"), InContainer(""))));
+ EXPECT_THAT(getSymbols("Color1"),
+ ElementsAre(AllOf(Named("Color1"), InContainer(""))));
+ EXPECT_THAT(getSymbols("Green"),
+ ElementsAre(AllOf(Named("Green"), InContainer(""))));
+ EXPECT_THAT(getSymbols("Color2"),
+ ElementsAre(AllOf(Named("Color2"), InContainer(""))));
+ EXPECT_THAT(getSymbols("Yellow"), IsEmpty());
+ EXPECT_THAT(getSymbols("Color2::Yellow"), IsEmpty());
+ EXPECT_THAT(getSymbols("ns"),
+ ElementsAre(AllOf(Named("ns"), InContainer(""))));
+ EXPECT_THAT(getSymbols("Black"),
+ ElementsAre(AllOf(Named("Black"), InContainer("ns::"))));
+ EXPECT_THAT(getSymbols("ns::Black"),
+ ElementsAre(AllOf(Named("Black"), InContainer("ns::"))));
+}
+
+TEST_F(WorkspaceSymbolsTest, Union) {
+ addFile("foo.h", R"cpp(
+ union U {
+ int x;
+ bool y;
+ };
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("U"), ElementsAre(AllOf(Named("U"), InContainer(""))));
+ EXPECT_THAT(getSymbols("x"), IsEmpty());
+ EXPECT_THAT(getSymbols("y"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, InlineNamespace) {
+ addFile("foo.h", R"cpp(
+ namespace na {
+ inline namespace nb {
+ class Foo {};
+ }
+ }
+ namespace na {
+ // This is still inlined.
+ namespace nb {
+ class Bar {};
+ }
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+ EXPECT_THAT(getSymbols("na"),
+ ElementsAre(AllOf(Named("na"), InContainer(""))));
+ EXPECT_THAT(getSymbols("nb"),
+ ElementsAre(AllOf(Named("nb"), InContainer("na::"))));
+ EXPECT_THAT(getSymbols("Foo"),
+ ElementsAre(AllOf(Named("Foo"), InContainer("na::"))));
+ EXPECT_THAT(getSymbols("na::Foo"),
+ ElementsAre(AllOf(Named("Foo"), InContainer("na::"))));
+ // It would be good if it was possible to query with the inline namespace as
+ // well.
+ // EXPECT_THAT(getSymbols("na::nb::Foo"), ElementsAre(AllOf(Named("Foo"),
+ // InContainer("na::Foo"))));
+ EXPECT_THAT(getSymbols("Bar"),
+ ElementsAre(AllOf(Named("Bar"), InContainer("na::"))));
+ EXPECT_THAT(getSymbols("na::Bar"),
+ ElementsAre(AllOf(Named("Bar"), InContainer("na::"))));
+ EXPECT_THAT(getSymbols("nb::Bar"), IsEmpty());
+}
+
+TEST_F(WorkspaceSymbolsTest, SymbolKindCapabilities) {
+ addFile("foo.h", R"cpp(
+ struct Foo {};
+ class Foo2 {};
+ enum {
+ FOO_VAL
+ }
+ )cpp");
+ addFile("foo.cpp", R"cpp(
+ #include "foo.h"
+ )cpp");
+
+ EXPECT_THAT(
+ getSymbols("Foo"),
+ UnorderedElementsAre(
+ AllOf(Named("Foo"), InContainer(""), WithKind(SymbolKind::Class)),
+ AllOf(Named("Foo2"), InContainer(""), WithKind(SymbolKind::Class)),
+ AllOf(Named("FOO_VAL"), InContainer(""),
+ WithKind(SymbolKind::Enum))));
+
+ using SymbolKindType = std::underlying_type<SymbolKind>::type;
+ std::vector<SymbolKind> BaseKinds;
+ for (SymbolKindType I = 0; I < SymbolKindType(SymbolKind::Array); ++I)
+ BaseKinds.push_back(SymbolKind(I));
+
+ Opts->supportedSymbolKinds = BaseKinds;
+ EXPECT_THAT(
+ getSymbols("Foo"),
+ UnorderedElementsAre(
+ AllOf(Named("Foo"), InContainer(""), WithKind(SymbolKind::Class)),
+ AllOf(Named("Foo2"), InContainer(""), WithKind(SymbolKind::Class)),
+ AllOf(Named("FOO_VAL"), InContainer(""),
+ WithKind(SymbolKind::Enum))));
+
+ Opts->supportedSymbolKinds->push_back(SymbolKind::Struct);
+ Opts->supportedSymbolKinds->push_back(SymbolKind::EnumMember);
+ EXPECT_THAT(
+ getSymbols("Foo"),
+ UnorderedElementsAre(
+ AllOf(Named("Foo"), InContainer(""), WithKind(SymbolKind::Struct)),
+ AllOf(Named("Foo2"), InContainer(""), WithKind(SymbolKind::Class)),
+ AllOf(Named("FOO_VAL"), InContainer(""),
+ WithKind(SymbolKind::EnumMember))));
+}
+
+} // namespace clangd
+} // namespace clang
Index: unittests/clangd/CMakeLists.txt
===================================================================
--- unittests/clangd/CMakeLists.txt
+++ unittests/clangd/CMakeLists.txt
@@ -17,6 +17,7 @@
ContextTests.cpp
DraftStoreTests.cpp
FileIndexTests.cpp
+ FindSymbolsTests.cpp
FuzzyMatchTests.cpp
HeadersTests.cpp
IndexTests.cpp
Index: test/clangd/initialize-params.test
===================================================================
--- test/clangd/initialize-params.test
+++ test/clangd/initialize-params.test
@@ -36,7 +36,8 @@
# CHECK-NEXT: ","
# CHECK-NEXT: ]
# CHECK-NEXT: },
-# CHECK-NEXT: "textDocumentSync": 2
+# CHECK-NEXT: "textDocumentSync": 2,
+# CHECK-NEXT: "workspaceSymbolProvider": true
# CHECK-NEXT: }
# CHECK-NEXT: }
---
Index: test/clangd/initialize-params-invalid.test
===================================================================
--- test/clangd/initialize-params-invalid.test
+++ test/clangd/initialize-params-invalid.test
@@ -36,7 +36,8 @@
# CHECK-NEXT: ","
# CHECK-NEXT: ]
# CHECK-NEXT: },
-# CHECK-NEXT: "textDocumentSync": 2
+# CHECK-NEXT: "textDocumentSync": 2,
+# CHECK-NEXT: "workspaceSymbolProvider": true
# CHECK-NEXT: }
# CHECK-NEXT: }
---
Index: clangd/tool/ClangdMain.cpp
===================================================================
--- clangd/tool/ClangdMain.cpp
+++ clangd/tool/ClangdMain.cpp
@@ -96,9 +96,9 @@
clEnumValN(PCHStorageFlag::Memory, "memory", "store PCHs in memory")),
llvm::cl::init(PCHStorageFlag::Disk));
-static llvm::cl::opt<int> LimitCompletionResult(
- "completion-limit",
- llvm::cl::desc("Limit the number of completion results returned by clangd. "
+static llvm::cl::opt<int> LimitResults(
+ "limit-results",
+ llvm::cl::desc("Limit the number of results returned by clangd. "
"0 means no limit."),
llvm::cl::init(100));
@@ -118,11 +118,11 @@
"Mirror all LSP input to the specified file. Useful for debugging."),
llvm::cl::init(""), llvm::cl::Hidden);
-static llvm::cl::opt<bool> EnableIndexBasedCompletion(
- "enable-index-based-completion",
- llvm::cl::desc(
- "Enable index-based global code completion. "
- "Clang uses an index built from symbols in opened files"),
+static llvm::cl::opt<bool> EnableIndex(
+ "index",
+ llvm::cl::desc("Enable index-based features such as global code completion "
+ "and searching for symbols."
+ "Clang uses an index built from symbols in opened files"),
llvm::cl::init(true));
static llvm::cl::opt<Path> YamlSymbolFile(
@@ -220,20 +220,23 @@
}
if (!ResourceDir.empty())
Opts.ResourceDir = ResourceDir;
- Opts.BuildDynamicSymbolIndex = EnableIndexBasedCompletion;
+ Opts.BuildDynamicSymbolIndex = EnableIndex;
std::unique_ptr<SymbolIndex> StaticIdx;
- if (EnableIndexBasedCompletion && !YamlSymbolFile.empty()) {
+ if (EnableIndex && !YamlSymbolFile.empty()) {
StaticIdx = BuildStaticIndex(YamlSymbolFile);
Opts.StaticIndex = StaticIdx.get();
}
Opts.AsyncThreadsCount = WorkerThreadsCount;
clangd::CodeCompleteOptions CCOpts;
CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
- CCOpts.Limit = LimitCompletionResult;
+ CCOpts.Limit = LimitResults;
+ clangd::WorkspaceSymbolOptions WorkspaceSymOpts;
+ WorkspaceSymOpts.Limit = LimitResults;
// Initialize and run ClangdLSPServer.
- ClangdLSPServer LSPServer(Out, CCOpts, CompileCommandsDirPath, Opts);
+ ClangdLSPServer LSPServer(Out, CCOpts, WorkspaceSymOpts,
+ CompileCommandsDirPath, Opts);
constexpr int NoShutdownRequestErrorCode = 1;
llvm::set_thread_name("clangd.main");
// Change stdin to binary to not lose \r\n on windows.
Index: clangd/index/SymbolCollector.cpp
===================================================================
--- clangd/index/SymbolCollector.cpp
+++ clangd/index/SymbolCollector.cpp
@@ -11,6 +11,7 @@
#include "../AST.h"
#include "../CodeCompletionStrings.h"
#include "../Logger.h"
+#include "../SourceCode.h"
#include "../URI.h"
#include "CanonicalIncludes.h"
#include "clang/AST/DeclCXX.h"
@@ -80,16 +81,6 @@
return llvm::None;
}
-// "a::b::c", return {"a::b::", "c"}. Scope is empty if there's no qualifier.
-std::pair<llvm::StringRef, llvm::StringRef>
-splitQualifiedName(llvm::StringRef QName) {
- assert(!QName.startswith("::") && "Qualified names should not start with ::");
- size_t Pos = QName.rfind("::");
- if (Pos == llvm::StringRef::npos)
- return {StringRef(), QName};
- return {QName.substr(0, Pos + 2), QName.substr(Pos + 2)};
-}
-
bool shouldFilterDecl(const NamedDecl *ND, ASTContext *ASTCtx,
const SymbolCollector::Options &Opts) {
using namespace clang::ast_matchers;
@@ -299,6 +290,8 @@
Symbol S;
S.ID = std::move(ID);
+ assert(!StringRef(QName).startswith("::") &&
+ "Qualified names should not start with '::' here.");
std::tie(S.Scope, S.Name) = splitQualifiedName(QName);
S.SymInfo = index::getSymbolInfo(&ND);
std::string FileURI;
Index: clangd/XRefs.cpp
===================================================================
--- clangd/XRefs.cpp
+++ clangd/XRefs.cpp
@@ -143,45 +143,14 @@
}
};
-llvm::Optional<Location>
-makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
- const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
- const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
- SourceLocation LocStart = ValSourceRange.getBegin();
-
- const FileEntry *F =
- SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
- if (!F)
- return llvm::None;
- SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(), 0,
- SourceMgr, LangOpts);
- Position Begin = sourceLocToPosition(SourceMgr, LocStart);
- Position End = sourceLocToPosition(SourceMgr, LocEnd);
- Range R = {Begin, End};
- Location L;
-
- SmallString<64> FilePath = F->tryGetRealPathName();
- if (FilePath.empty())
- FilePath = F->getName();
- if (!llvm::sys::path::is_absolute(FilePath)) {
- if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) {
- log("Could not turn relative path to absolute: " + FilePath);
- return llvm::None;
- }
- }
-
- L.uri = URIForFile(FilePath.str());
- L.range = R;
- return L;
-}
-
} // namespace
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos) {
const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
if (!FE)
return {};
+ const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
@@ -213,14 +182,16 @@
for (auto D : Decls) {
auto Loc = findNameLoc(D);
- auto L = makeLocation(AST, SourceRange(Loc, Loc));
+ auto EndLoc = Lexer::getLocForEndOfToken(Loc, 0, SourceMgr, LangOpts);
+ auto L = sourceRangeToLocation(SourceMgr, SourceRange(Loc, EndLoc));
if (L)
Result.push_back(*L);
}
for (auto Item : MacroInfos) {
auto Loc = Item.Info->getDefinitionLoc();
- auto L = makeLocation(AST, SourceRange(Loc, Loc));
+ auto EndLoc = Lexer::getLocForEndOfToken(Loc, 0, SourceMgr, LangOpts);
+ auto L = sourceRangeToLocation(SourceMgr, SourceRange(Loc, EndLoc));
if (L)
Result.push_back(*L);
}
Index: clangd/SourceCode.h
===================================================================
--- clangd/SourceCode.h
+++ clangd/SourceCode.h
@@ -49,6 +49,22 @@
// Note that clang also uses closed source ranges, which this can't handle!
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R);
+/// Turn a SourceRange into a Location.
+llvm::Optional<Location>
+sourceRangeToLocation(const SourceManager &SourceMgr,
+ const SourceRange &ValSourceRange);
+
+/// Turn a pair of offsets into a Location.
+llvm::Optional<Location> offsetRangeToLocation(SourceManager &SourceMgr,
+ StringRef File,
+ size_t OffsetStart,
+ size_t OffsetEnd);
+
+/// From "a::b::c", return {"a::b::", "c"}. Scope is empty if there's no
+/// qualifier.
+std::pair<llvm::StringRef, llvm::StringRef>
+splitQualifiedName(llvm::StringRef QName);
+
} // namespace clangd
} // namespace clang
#endif
Index: clangd/SourceCode.cpp
===================================================================
--- clangd/SourceCode.cpp
+++ clangd/SourceCode.cpp
@@ -7,10 +7,12 @@
//
//===----------------------------------------------------------------------===//
#include "SourceCode.h"
+#include "Logger.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
namespace clang {
namespace clangd {
@@ -76,5 +78,62 @@
return {Begin, End};
}
+llvm::Optional<Location>
+sourceRangeToLocation(const SourceManager &SourceMgr,
+ const SourceRange &ValSourceRange) {
+ SourceLocation LocStart = ValSourceRange.getBegin();
+ const FileEntry *FE =
+ SourceMgr.getFileEntryForID(SourceMgr.getFileID(LocStart));
+ if (!FE)
+ return llvm::None;
+ SourceLocation LocEnd = ValSourceRange.getEnd();
+ Position Begin = sourceLocToPosition(SourceMgr, LocStart);
+ Position End = sourceLocToPosition(SourceMgr, LocEnd);
+ Range R = {Begin, End};
+ Location L;
+
+ SmallString<64> FilePath = FE->tryGetRealPathName();
+ if (FilePath.empty())
+ FilePath = FE->getName();
+ if (!llvm::sys::path::is_absolute(FilePath)) {
+ if (!SourceMgr.getFileManager().makeAbsolutePath(FilePath)) {
+ log("Could not turn relative path to absolute: " + FilePath);
+ return llvm::None;
+ }
+ }
+
+ L.uri = URIForFile(FilePath.str());
+ L.range = R;
+ return L;
+}
+
+llvm::Optional<Location> offsetRangeToLocation(SourceManager &SourceMgr,
+ StringRef File,
+ size_t OffsetStart,
+ size_t OffsetEnd) {
+ const FileEntry *FE = SourceMgr.getFileManager().getFile(File);
+ if (!FE)
+ return llvm::None;
+
+ FileID FID = SourceMgr.getOrCreateFileID(FE, SrcMgr::C_User);
+
+ SourceLocation LocStart = SourceMgr.getComposedLoc(FID, OffsetStart);
+ SourceLocation LocEnd = SourceMgr.getComposedLoc(FID, OffsetEnd);
+ if (LocStart.isInvalid() || LocEnd.isInvalid())
+ return llvm::None;
+
+ return sourceRangeToLocation(SourceMgr, {LocStart, LocEnd});
+}
+
+/// From "a::b::c", return {"a::b::", "c"}. Scope is empty if there's no
+/// qualifier.
+std::pair<llvm::StringRef, llvm::StringRef>
+splitQualifiedName(llvm::StringRef QName) {
+ size_t Pos = QName.rfind("::");
+ if (Pos == llvm::StringRef::npos)
+ return {StringRef(), QName};
+ return {QName.substr(0, Pos + 2), QName.substr(Pos + 2)};
+}
+
} // namespace clangd
} // namespace clang
Index: clangd/ProtocolHandlers.h
===================================================================
--- clangd/ProtocolHandlers.h
+++ clangd/ProtocolHandlers.h
@@ -49,6 +49,7 @@
virtual void onSwitchSourceHeader(TextDocumentIdentifier &Params) = 0;
virtual void onFileEvent(DidChangeWatchedFilesParams &Params) = 0;
virtual void onCommand(ExecuteCommandParams &Params) = 0;
+ virtual void onWorkspaceSymbol(WorkspaceSymbolParams &Params) = 0;
virtual void onRename(RenameParams &Parames) = 0;
virtual void onDocumentHighlight(TextDocumentPositionParams &Params) = 0;
virtual void onHover(TextDocumentPositionParams &Params) = 0;
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -72,4 +72,5 @@
&ProtocolCallbacks::onDocumentHighlight);
Register("workspace/didChangeConfiguration",
&ProtocolCallbacks::onChangeConfiguration);
+ Register("workspace/symbol", &ProtocolCallbacks::onWorkspaceSymbol);
}
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -237,6 +237,59 @@
};
bool fromJSON(const json::Expr &, CompletionClientCapabilities &);
+/// A symbol kind.
+enum class SymbolKind {
+ File = 1,
+ Module = 2,
+ Namespace = 3,
+ Package = 4,
+ Class = 5,
+ Method = 6,
+ Property = 7,
+ Field = 8,
+ Constructor = 9,
+ Enum = 10,
+ Interface = 11,
+ Function = 12,
+ Variable = 13,
+ Constant = 14,
+ String = 15,
+ Number = 16,
+ Boolean = 17,
+ Array = 18,
+ Object = 19,
+ Key = 20,
+ Null = 21,
+ EnumMember = 22,
+ Struct = 23,
+ Event = 24,
+ Operator = 25,
+ TypeParameter = 26
+};
+bool fromJSON(const json::Expr &, SymbolKind &);
+
+struct SymbolKindCapabilities {
+ /// The SymbolKinds that the client supports. If not set, the client only
+ /// supports <= SymbolKind::Array and will not fall back to a valid default
+ /// value.
+ llvm::Optional<std::vector<SymbolKind>> valueSet;
+};
+bool fromJSON(const json::Expr &, SymbolKindCapabilities &);
+
+struct WorkspaceSymbolCapabilities {
+ /// Capabilities SymbolKind.
+ llvm::Optional<SymbolKindCapabilities> symbolKind;
+};
+bool fromJSON(const json::Expr &, WorkspaceSymbolCapabilities &);
+
+// FIXME: most of the capabilities are missing from this struct. Only the ones
+// used by clangd are currently there.
+struct WorkspaceClientCapabilities {
+ /// Capabilities specific to `workspace/symbol`.
+ llvm::Optional<WorkspaceSymbolCapabilities> symbol;
+};
+bool fromJSON(const json::Expr &, WorkspaceClientCapabilities &);
+
// FIXME: most of the capabilities are missing from this struct. Only the ones
// used by clangd are currently there.
struct TextDocumentClientCapabilities {
@@ -247,8 +300,7 @@
struct ClientCapabilities {
// Workspace specific client capabilities.
- // NOTE: not used by clangd at the moment.
- // WorkspaceClientCapabilities workspace;
+ llvm::Optional<WorkspaceClientCapabilities> workspace;
// Text document specific client capabilities.
TextDocumentClientCapabilities textDocument;
@@ -525,6 +577,30 @@
json::Expr toJSON(const Command &C);
+/// Represents information about programming constructs like variables, classes,
+/// interfaces etc.
+struct SymbolInformation {
+ /// The name of this symbol.
+ std::string name;
+
+ /// The kind of this symbol.
+ SymbolKind kind;
+
+ /// The location of this symbol.
+ Location location;
+
+ /// The name of the symbol containing this symbol.
+ std::string containerName;
+};
+json::Expr toJSON(const SymbolInformation &);
+
+/// The parameters of a Workspace Symbol Request.
+struct WorkspaceSymbolParams {
+ /// A non-empty query string
+ std::string query;
+};
+bool fromJSON(const json::Expr &, WorkspaceSymbolParams &);
+
struct ApplyWorkspaceEditParams {
WorkspaceEdit edit;
};
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -176,6 +176,41 @@
return true;
}
+bool fromJSON(const json::Expr &E, SymbolKind &Out) {
+ if (auto T = E.asInteger()) {
+ if (*T < static_cast<int>(SymbolKind::File) ||
+ *T > static_cast<int>(SymbolKind::TypeParameter))
+ return false;
+ Out = static_cast<SymbolKind>(*T);
+ return true;
+ }
+ return false;
+}
+
+bool fromJSON(const json::Expr &Params, SymbolKindCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("valueSet", R.valueSet);
+ return true;
+}
+
+bool fromJSON(const json::Expr &Params, WorkspaceSymbolCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("symbolKind", R.symbolKind);
+ return true;
+}
+
+bool fromJSON(const json::Expr &Params, WorkspaceClientCapabilities &R) {
+ json::ObjectMapper O(Params);
+ if (!O)
+ return false;
+ O.map("symbol", R.symbol);
+ return true;
+}
+
bool fromJSON(const json::Expr &Params, TextDocumentClientCapabilities &R) {
json::ObjectMapper O(Params);
if (!O)
@@ -351,6 +386,20 @@
return false; // Unrecognized command.
}
+json::Expr toJSON(const SymbolInformation &P) {
+ return json::obj{
+ {"name", P.name},
+ {"kind", static_cast<int>(P.kind)},
+ {"location", P.location},
+ {"containerName", P.containerName},
+ };
+}
+
+bool fromJSON(const json::Expr &Params, WorkspaceSymbolParams &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("query", R.query);
+}
+
json::Expr toJSON(const Command &C) {
auto Cmd = json::obj{{"title", C.title}, {"command", C.command}};
if (C.workspaceEdit)
Index: clangd/FindSymbols.h
===================================================================
--- /dev/null
+++ clangd/FindSymbols.h
@@ -0,0 +1,41 @@
+//===--- FindSymbols.h --------------------------------------*- C++-*------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Queries that provide a list of symbols matching a string.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_WORKSPACESYMBOL_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_WORKSPACESYMBOL_H
+
+#include "Protocol.h"
+#include "clang/Basic/VirtualFileSystem.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+namespace clangd {
+class SymbolIndex;
+
+struct WorkspaceSymbolOptions {
+ /// Limit the number of results returned (0 means no limit).
+ size_t Limit = 0;
+
+ /// Symbol kinds supported by the requester.
+ llvm::Optional<std::vector<SymbolKind>> supportedSymbolKinds;
+};
+
+llvm::Expected<std::vector<SymbolInformation>>
+getWorkspaceSymbols(llvm::StringRef Query, const WorkspaceSymbolOptions &Opts,
+ const SymbolIndex *const Index,
+ llvm::IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
Index: clangd/FindSymbols.cpp
===================================================================
--- /dev/null
+++ clangd/FindSymbols.cpp
@@ -0,0 +1,169 @@
+//===--- FindSymbols.cpp ------------------------------------*- C++-*------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "FindSymbols.h"
+
+#include "Logger.h"
+#include "SourceCode.h"
+#include "index/Index.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Index/IndexSymbol.h"
+#include "llvm/Support/FormatVariadic.h"
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+SymbolKind adjustKindToCapability(
+ SymbolKind Kind,
+ const llvm::Optional<std::vector<SymbolKind>> &supportedSymbolKinds) {
+ // All clients should support those.
+ if (Kind >= SymbolKind::File && Kind <= SymbolKind::Array)
+ return Kind;
+
+ if (supportedSymbolKinds &&
+ std::find(supportedSymbolKinds->begin(), supportedSymbolKinds->end(),
+ Kind) != supportedSymbolKinds->end())
+ return Kind;
+
+ // Provide some fall backs for common kinds that are close enough.
+ if (Kind == SymbolKind::Struct)
+ return SymbolKind::Class;
+ if (Kind == SymbolKind::EnumMember)
+ return SymbolKind::Enum;
+
+ if (!supportedSymbolKinds) {
+ // Provide some sensible default when all fails.
+ return SymbolKind::Variable;
+ }
+ return Kind;
+}
+
+// Convert a index::SymbolKind to clangd::SymbolKind (LSP)
+// Note, some are not perfect matches and should be improved when this LSP
+// issue is addressed:
+// https://github.com/Microsoft/language-server-protocol/issues/344
+SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) {
+ switch (Kind) {
+ case index::SymbolKind::Unknown:
+ return SymbolKind::Variable;
+ case index::SymbolKind::Module:
+ return SymbolKind::Module;
+ case index::SymbolKind::Namespace:
+ return SymbolKind::Namespace;
+ case index::SymbolKind::NamespaceAlias:
+ return SymbolKind::Namespace;
+ case index::SymbolKind::Macro:
+ return SymbolKind::String;
+ case index::SymbolKind::Enum:
+ return SymbolKind::Enum;
+ case index::SymbolKind::Struct:
+ return SymbolKind::Struct;
+ case index::SymbolKind::Class:
+ return SymbolKind::Class;
+ case index::SymbolKind::Protocol:
+ return SymbolKind::Interface;
+ case index::SymbolKind::Extension:
+ return SymbolKind::Interface;
+ case index::SymbolKind::Union:
+ return SymbolKind::Class;
+ case index::SymbolKind::TypeAlias:
+ return SymbolKind::Class;
+ case index::SymbolKind::Function:
+ return SymbolKind::Function;
+ case index::SymbolKind::Variable:
+ return SymbolKind::Variable;
+ case index::SymbolKind::Field:
+ return SymbolKind::Field;
+ case index::SymbolKind::EnumConstant:
+ return SymbolKind::EnumMember;
+ case index::SymbolKind::InstanceMethod:
+ case index::SymbolKind::ClassMethod:
+ case index::SymbolKind::StaticMethod:
+ return SymbolKind::Method;
+ case index::SymbolKind::InstanceProperty:
+ case index::SymbolKind::ClassProperty:
+ case index::SymbolKind::StaticProperty:
+ return SymbolKind::Property;
+ case index::SymbolKind::Constructor:
+ case index::SymbolKind::Destructor:
+ return SymbolKind::Method;
+ case index::SymbolKind::ConversionFunction:
+ return SymbolKind::Function;
+ case index::SymbolKind::Parameter:
+ return SymbolKind::Variable;
+ case index::SymbolKind::Using:
+ return SymbolKind::Namespace;
+ }
+ llvm_unreachable("invalid symbol kind");
+}
+} // namespace
+
+llvm::Expected<std::vector<SymbolInformation>>
+getWorkspaceSymbols(StringRef Query, const WorkspaceSymbolOptions &Opts,
+ const SymbolIndex *const Index,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+ std::vector<SymbolInformation> Result;
+ if (Query.empty() || !Index)
+ return Result;
+
+ auto Names = splitQualifiedName(Query);
+
+ // We'll use a temporary SourceManager to do the offset -> line/col mapping.
+ // We don't have any context from which this query was launched (working dir),
+ // so use defaults here.
+ // FIXME: If the index stored line/col directly, we woudln't have to read all
+ // the files here.
+ FileSystemOptions FileOpts;
+ FileManager FM(FileOpts, VFS);
+ IntrusiveRefCntPtr<DiagnosticsEngine> DE(
+ CompilerInstance::createDiagnostics(new DiagnosticOptions));
+ SourceManager TempSM(*DE, FM);
+
+ // Global scope is represented by "" in FuzzyFind.
+ if (Names.first.startswith("::"))
+ Names.first = Names.first.substr(2);
+
+ FuzzyFindRequest Req;
+ Req.Query = Names.second;
+ if (!Names.first.empty())
+ Req.Scopes.push_back(Names.first);
+ if (Opts.Limit)
+ Req.MaxCandidateCount = Opts.Limit;
+ Index->fuzzyFind(Req, [&TempSM, &Result, &Opts](const Symbol &Sym) {
+ auto &CD = Sym.Definition ? Sym.Definition : Sym.CanonicalDeclaration;
+ auto Uri = URI::parse(CD.FileURI);
+ if (!Uri) {
+ log(llvm::formatv(
+ "Workspace symbol: Could not parse URI '{0}' for symbol '{1}'.",
+ CD.FileURI, Sym.Name));
+ return;
+ }
+ auto Path = URI::resolve(*Uri);
+ if (!Path) {
+ log(llvm::formatv("Workspace symbol: Could not resolve path for URI "
+ "'{0}' for symbol '{1}'.",
+ (*Uri).toString(), Sym.Name.str()));
+ return;
+ }
+ auto L =
+ offsetRangeToLocation(TempSM, *Path, CD.StartOffset, CD.StartOffset);
+ if (L) {
+ SymbolKind SK =
+ adjustKindToCapability(indexSymbolKindToSymbolKind(Sym.SymInfo.Kind),
+ Opts.supportedSymbolKinds);
+ Result.push_back({Sym.Name, SK, *L, Sym.Scope});
+ }
+ });
+ return Result;
+}
+
+} // namespace clangd
+} // namespace clang
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -33,6 +33,7 @@
class PCHContainerOperations;
namespace clangd {
+struct WorkspaceSymbolOptions;
class DiagnosticsConsumer {
public:
@@ -157,6 +158,10 @@
/// Get code hover for a given position.
void findHover(PathRef File, Position Pos, Callback<Hover> CB);
+ void workspaceSymbols(StringRef Query,
+ const clangd::WorkspaceSymbolOptions &Opts,
+ Callback<std::vector<SymbolInformation>> CB);
+
/// Run formatting for \p Rng inside \p File with content \p Code.
llvm::Expected<tooling::Replacements> formatRange(StringRef Code,
PathRef File, Range Rng);
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -9,6 +9,7 @@
#include "ClangdServer.h"
#include "CodeComplete.h"
+#include "FindSymbols.h"
#include "Headers.h"
#include "SourceCode.h"
#include "XRefs.h"
@@ -492,6 +493,13 @@
// invalidating other caches.
}
+void ClangdServer::workspaceSymbols(
+ StringRef Query, const clangd::WorkspaceSymbolOptions &Opts,
+ Callback<std::vector<SymbolInformation>> CB) {
+ CB(clangd::getWorkspaceSymbols(Query, Opts, Index,
+ FSProvider.getFileSystem()));
+}
+
std::vector<std::pair<Path, std::size_t>>
ClangdServer::getUsedBytesPerFile() const {
return WorkScheduler.getUsedBytesPerFile();
Index: clangd/ClangdLSPServer.h
===================================================================
--- clangd/ClangdLSPServer.h
+++ clangd/ClangdLSPServer.h
@@ -12,6 +12,7 @@
#include "ClangdServer.h"
#include "DraftStore.h"
+#include "FindSymbols.h"
#include "GlobalCompilationDatabase.h"
#include "Path.h"
#include "Protocol.h"
@@ -33,6 +34,7 @@
/// loaded only from \p CompileCommandsDir. Otherwise, clangd will look
/// for compile_commands.json in all parent directories of each file.
ClangdLSPServer(JSONOutput &Out, const clangd::CodeCompleteOptions &CCOpts,
+ const clangd::WorkspaceSymbolOptions &WorkspaceSymOpts,
llvm::Optional<Path> CompileCommandsDir,
const ClangdServer::Options &Opts);
@@ -69,6 +71,7 @@
void onDocumentHighlight(TextDocumentPositionParams &Params) override;
void onFileEvent(DidChangeWatchedFilesParams &Params) override;
void onCommand(ExecuteCommandParams &Params) override;
+ void onWorkspaceSymbol(WorkspaceSymbolParams &Params) override;
void onRename(RenameParams &Parames) override;
void onHover(TextDocumentPositionParams &Params) override;
void onChangeConfiguration(DidChangeConfigurationParams &Params) override;
@@ -102,6 +105,8 @@
RealFileSystemProvider FSProvider;
/// Options used for code completion
clangd::CodeCompleteOptions CCOpts;
+ /// Options used for workspace symbol.
+ clangd::WorkspaceSymbolOptions WorkspaceSymbolOpts;
// Store of the current versions of the open documents.
DraftStore DraftMgr;
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -96,6 +96,10 @@
CCOpts.EnableSnippets =
Params.capabilities.textDocument.completion.completionItem.snippetSupport;
+ if (Params.capabilities.workspace && Params.capabilities.workspace->symbol &&
+ Params.capabilities.workspace->symbol->symbolKind)
+ WorkspaceSymbolOpts.supportedSymbolKinds =
+ Params.capabilities.workspace->symbol->symbolKind->valueSet;
reply(json::obj{
{{"capabilities",
@@ -122,6 +126,7 @@
{"documentHighlightProvider", true},
{"hoverProvider", true},
{"renameProvider", true},
+ {"workspaceSymbolProvider", true},
{"executeCommandProvider",
json::obj{
{"commands",
@@ -245,6 +250,17 @@
}
}
+void ClangdLSPServer::onWorkspaceSymbol(WorkspaceSymbolParams &Params) {
+ Server.workspaceSymbols(
+ Params.query, WorkspaceSymbolOpts,
+ [](llvm::Expected<std::vector<SymbolInformation>> Items) {
+ if (!Items)
+ return replyError(ErrorCode::InvalidParams,
+ llvm::toString(Items.takeError()));
+ reply(json::ary(*Items));
+ });
+}
+
void ClangdLSPServer::onRename(RenameParams &Params) {
Path File = Params.textDocument.uri.file();
llvm::Optional<std::string> Code = DraftMgr.getDraft(File);
@@ -417,11 +433,12 @@
}
}
-ClangdLSPServer::ClangdLSPServer(JSONOutput &Out,
- const clangd::CodeCompleteOptions &CCOpts,
- llvm::Optional<Path> CompileCommandsDir,
- const ClangdServer::Options &Opts)
+ClangdLSPServer::ClangdLSPServer(
+ JSONOutput &Out, const clangd::CodeCompleteOptions &CCOpts,
+ const clangd::WorkspaceSymbolOptions &WorkspaceSymOpts,
+ llvm::Optional<Path> CompileCommandsDir, const ClangdServer::Options &Opts)
: Out(Out), CDB(std::move(CompileCommandsDir)), CCOpts(CCOpts),
+ WorkspaceSymbolOpts(WorkspaceSymOpts),
Server(CDB, FSProvider, /*DiagConsumer=*/*this, Opts) {}
bool ClangdLSPServer::run(std::istream &In, JSONStreamStyle InputStyle) {
Index: clangd/CMakeLists.txt
===================================================================
--- clangd/CMakeLists.txt
+++ clangd/CMakeLists.txt
@@ -14,6 +14,7 @@
Context.cpp
Diagnostics.cpp
DraftStore.cpp
+ FindSymbols.cpp
FuzzyMatch.cpp
GlobalCompilationDatabase.cpp
Headers.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits