[clang-tools-extra] r306558 - [clangd] Add "Go to Declaration" functionality
Marc-Andre Laperle via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 28 09:12:10 PDT 2017
Author: malaperle
Date: Wed Jun 28 09:12:10 2017
New Revision: 306558
URL: http://llvm.org/viewvc/llvm-project?rev=306558&view=rev
Log:
[clangd] Add "Go to Declaration" functionality
Summary: This change allows to navigate to most identifiers' declarations in code. This is a first step towards implementing "Go to Definition". It reuses clangIndex in order to detect which occurrences corresponds to the position requested. The occurrences' Decls are then used to generate locations suitable for navigating to the declarations.
Reviewers: krasimir, bkramer, ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: cfe-commits, mgorny
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D34269
Added:
clang-tools-extra/trunk/test/clangd/definitions.test
Modified:
clang-tools-extra/trunk/clangd/CMakeLists.txt
clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
clang-tools-extra/trunk/clangd/ClangdServer.cpp
clang-tools-extra/trunk/clangd/ClangdServer.h
clang-tools-extra/trunk/clangd/ClangdUnit.cpp
clang-tools-extra/trunk/clangd/ClangdUnit.h
clang-tools-extra/trunk/clangd/Protocol.cpp
clang-tools-extra/trunk/clangd/Protocol.h
clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
clang-tools-extra/trunk/clangd/ProtocolHandlers.h
clang-tools-extra/trunk/test/clangd/formatting.test
Modified: clang-tools-extra/trunk/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/CMakeLists.txt Wed Jun 28 09:12:10 2017
@@ -18,6 +18,7 @@ add_clang_library(clangDaemon
clangBasic
clangFormat
clangFrontend
+ clangIndex
clangSema
clangTooling
clangToolingCore
Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Wed Jun 28 09:12:10 2017
@@ -69,6 +69,8 @@ public:
JSONOutput &Out) override;
void onCompletion(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) override;
+ void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
+ JSONOutput &Out) override;
private:
ClangdLSPServer &LangServer;
@@ -84,7 +86,8 @@ void ClangdLSPServer::LSPProtocolCallbac
"documentRangeFormattingProvider": true,
"documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
"codeActionProvider": true,
- "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]}
+ "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]},
+ "definitionProvider": true
}}})");
}
@@ -191,6 +194,25 @@ void ClangdLSPServer::LSPProtocolCallbac
R"(,"result":[)" + Completions + R"(]})");
}
+void ClangdLSPServer::LSPProtocolCallbacks::onGoToDefinition(
+ TextDocumentPositionParams Params, StringRef ID, JSONOutput &Out) {
+
+ auto Items = LangServer.Server.findDefinitions(
+ Params.textDocument.uri.file,
+ Position{Params.position.line, Params.position.character}).Value;
+
+ std::string Locations;
+ for (const auto &Item : Items) {
+ Locations += Location::unparse(Item);
+ Locations += ",";
+ }
+ if (!Locations.empty())
+ Locations.pop_back();
+ Out.writeMessage(
+ R"({"jsonrpc":"2.0","id":)" + ID.str() +
+ R"(,"result":[)" + Locations + R"(]})");
+}
+
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, bool RunSynchronously)
: Out(Out), DiagConsumer(*this),
Server(CDB, DiagConsumer, FSProvider, RunSynchronously) {}
Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Wed Jun 28 09:12:10 2017
@@ -271,3 +271,17 @@ std::string ClangdServer::dumpAST(PathRe
});
return DumpFuture.get();
}
+
+Tagged<std::vector<Location>>
+ClangdServer::findDefinitions(PathRef File, Position Pos) {
+ auto FileContents = DraftMgr.getDraft(File);
+ assert(FileContents.Draft && "findDefinitions is called for non-added document");
+
+ std::vector<Location> Result;
+ auto TaggedFS = FSProvider.getTaggedFileSystem(File);
+ Units.runOnUnit(File, *FileContents.Draft, ResourceDir, CDB, PCHs,
+ TaggedFS.Value, [&](ClangdUnit &Unit) {
+ Result = Unit.findDefinitions(Pos);
+ });
+ return make_tagged(std::move(Result), TaggedFS.Tag);
+}
Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Wed Jun 28 09:12:10 2017
@@ -179,6 +179,8 @@ public:
Tagged<std::vector<CompletionItem>>
codeComplete(PathRef File, Position Pos,
llvm::Optional<StringRef> OverridenContents = llvm::None);
+ /// Get definition of symbol at a specified \p Line and \p Column in \p File.
+ Tagged<std::vector<Location>> findDefinitions(PathRef File, Position Pos);
/// Run formatting for \p Rng inside \p File.
std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Wed Jun 28 09:12:10 2017
@@ -8,13 +8,21 @@
//===---------------------------------------------------------------------===//
#include "ClangdUnit.h"
+
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/IndexDataConsumer.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/Format.h"
+#include <algorithm>
+
using namespace clang::clangd;
using namespace clang;
@@ -259,3 +267,145 @@ std::vector<DiagWithFixIts> ClangdUnit::
void ClangdUnit::dumpAST(llvm::raw_ostream &OS) const {
Unit->getASTContext().getTranslationUnitDecl()->dump(OS, true);
}
+
+namespace {
+/// Finds declarations locations that a given source location refers to.
+class DeclarationLocationsFinder : public index::IndexDataConsumer {
+ std::vector<Location> DeclarationLocations;
+ const SourceLocation &SearchedLocation;
+ ASTUnit &Unit;
+public:
+ DeclarationLocationsFinder(raw_ostream &OS,
+ const SourceLocation &SearchedLocation, ASTUnit &Unit) :
+ SearchedLocation(SearchedLocation), Unit(Unit) {
+ }
+
+ std::vector<Location> takeLocations() {
+ // Don't keep the same location multiple times.
+ // This can happen when nodes in the AST are visited twice.
+ std::sort(DeclarationLocations.begin(), DeclarationLocations.end());
+ auto last = std::unique(DeclarationLocations.begin(), DeclarationLocations.end());
+ DeclarationLocations.erase(last, DeclarationLocations.end());
+ return std::move(DeclarationLocations);
+ }
+
+ bool handleDeclOccurence(const Decl* D, index::SymbolRoleSet Roles,
+ ArrayRef<index::SymbolRelation> Relations, FileID FID, unsigned Offset,
+ index::IndexDataConsumer::ASTNodeInfo ASTNode) override
+ {
+ if (isSearchedLocation(FID, Offset)) {
+ addDeclarationLocation(D->getSourceRange());
+ }
+ return true;
+ }
+
+private:
+ bool isSearchedLocation(FileID FID, unsigned Offset) const {
+ const SourceManager &SourceMgr = Unit.getSourceManager();
+ return SourceMgr.getFileOffset(SearchedLocation) == Offset
+ && SourceMgr.getFileID(SearchedLocation) == FID;
+ }
+
+ void addDeclarationLocation(const SourceRange& ValSourceRange) {
+ const SourceManager& SourceMgr = Unit.getSourceManager();
+ const LangOptions& LangOpts = Unit.getLangOpts();
+ SourceLocation LocStart = ValSourceRange.getBegin();
+ SourceLocation LocEnd = Lexer::getLocForEndOfToken(ValSourceRange.getEnd(),
+ 0, SourceMgr, LangOpts);
+ Position P1;
+ P1.line = SourceMgr.getSpellingLineNumber(LocStart) - 1;
+ P1.character = SourceMgr.getSpellingColumnNumber(LocStart) - 1;
+ Position P2;
+ P2.line = SourceMgr.getSpellingLineNumber(LocEnd) - 1;
+ P2.character = SourceMgr.getSpellingColumnNumber(LocEnd) - 1;
+ Range R = { P1, P2 };
+ Location L;
+ L.uri = URI::fromFile(
+ SourceMgr.getFilename(SourceMgr.getSpellingLoc(LocStart)));
+ L.range = R;
+ DeclarationLocations.push_back(L);
+ }
+
+ void finish() override
+ {
+ // Also handle possible macro at the searched location.
+ Token Result;
+ if (!Lexer::getRawToken(SearchedLocation, Result, Unit.getSourceManager(),
+ Unit.getASTContext().getLangOpts(), false)) {
+ if (Result.is(tok::raw_identifier)) {
+ Unit.getPreprocessor().LookUpIdentifierInfo(Result);
+ }
+ IdentifierInfo* IdentifierInfo = Result.getIdentifierInfo();
+ if (IdentifierInfo && IdentifierInfo->hadMacroDefinition()) {
+ std::pair<FileID, unsigned int> DecLoc =
+ Unit.getSourceManager().getDecomposedExpansionLoc(SearchedLocation);
+ // Get the definition just before the searched location so that a macro
+ // referenced in a '#undef MACRO' can still be found.
+ SourceLocation BeforeSearchedLocation = Unit.getLocation(
+ Unit.getSourceManager().getFileEntryForID(DecLoc.first),
+ DecLoc.second - 1);
+ MacroDefinition MacroDef =
+ Unit.getPreprocessor().getMacroDefinitionAtLoc(IdentifierInfo,
+ BeforeSearchedLocation);
+ MacroInfo* MacroInf = MacroDef.getMacroInfo();
+ if (MacroInf) {
+ addDeclarationLocation(
+ SourceRange(MacroInf->getDefinitionLoc(),
+ MacroInf->getDefinitionEndLoc()));
+ }
+ }
+ }
+ }
+};
+} // namespace
+
+std::vector<Location> ClangdUnit::findDefinitions(Position Pos) {
+ const FileEntry *FE = Unit->getFileManager().getFile(Unit->getMainFileName());
+ if (!FE)
+ return {};
+
+ SourceLocation SourceLocationBeg = getBeginningOfIdentifier(Pos, FE);
+
+ auto DeclLocationsFinder = std::make_shared<DeclarationLocationsFinder>(llvm::errs(),
+ SourceLocationBeg, *Unit);
+ index::IndexingOptions IndexOpts;
+ IndexOpts.SystemSymbolFilter =
+ index::IndexingOptions::SystemSymbolFilterKind::All;
+ IndexOpts.IndexFunctionLocals = true;
+ index::indexASTUnit(*Unit, DeclLocationsFinder, IndexOpts);
+
+ return DeclLocationsFinder->takeLocations();
+}
+
+SourceLocation ClangdUnit::getBeginningOfIdentifier(const Position &Pos,
+ const FileEntry *FE) const {
+ // The language server protocol uses zero-based line and column numbers.
+ // Clang uses one-based numbers.
+ SourceLocation InputLocation = Unit->getLocation(FE, Pos.line + 1,
+ Pos.character + 1);
+
+ if (Pos.character == 0) {
+ return InputLocation;
+ }
+
+ // This handle cases where the position is in the middle of a token or right
+ // after the end of a token. In theory we could just use GetBeginningOfToken
+ // to find the start of the token at the input position, but this doesn't
+ // work when right after the end, i.e. foo|.
+ // So try to go back by one and see if we're still inside the an identifier
+ // token. If so, Take the beginning of this token.
+ // (It should be the same identifier because you can't have two adjacent
+ // identifiers without another token in between.)
+ SourceLocation PeekBeforeLocation = Unit->getLocation(FE, Pos.line + 1,
+ Pos.character);
+ const SourceManager &SourceMgr = Unit->getSourceManager();
+ Token Result;
+ Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr,
+ Unit->getASTContext().getLangOpts(), false);
+ if (Result.is(tok::raw_identifier)) {
+ return Lexer::GetBeginningOfToken(PeekBeforeLocation, SourceMgr,
+ Unit->getASTContext().getLangOpts());
+ }
+
+ return InputLocation;
+}
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.h Wed Jun 28 09:12:10 2017
@@ -59,6 +59,8 @@ public:
std::vector<CompletionItem>
codeComplete(StringRef Contents, Position Pos,
IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+ /// Get definition of symbol at a specified \p Line and \p Column in \p File.
+ std::vector<Location> findDefinitions(Position Pos);
/// Returns diagnostics and corresponding FixIts for each diagnostic that are
/// located in the current file.
std::vector<DiagWithFixIts> getLocalDiagnostics() const;
@@ -71,6 +73,8 @@ private:
Path FileName;
std::unique_ptr<ASTUnit> Unit;
std::shared_ptr<PCHContainerOperations> PCHs;
+
+ SourceLocation getBeginningOfIdentifier(const Position& Pos, const FileEntry* FE) const;
};
} // namespace clangd
Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Wed Jun 28 09:12:10 2017
@@ -54,7 +54,7 @@ URI URI::parse(llvm::yaml::ScalarNode *P
}
std::string URI::unparse(const URI &U) {
- return U.uri;
+ return "\"" + U.uri + "\"";
}
llvm::Optional<TextDocumentIdentifier>
@@ -162,6 +162,14 @@ std::string Range::unparse(const Range &
return Result;
}
+std::string Location::unparse(const Location &P) {
+ std::string Result;
+ llvm::raw_string_ostream(Result) << llvm::format(
+ R"({"uri": %s, "range": %s})", URI::unparse(P.uri).c_str(),
+ Range::unparse(P.range).c_str());
+ return Result;
+}
+
llvm::Optional<TextDocumentItem>
TextDocumentItem::parse(llvm::yaml::MappingNode *Params) {
TextDocumentItem Result;
Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Wed Jun 28 09:12:10 2017
@@ -38,6 +38,18 @@ struct URI {
static URI parse(llvm::yaml::ScalarNode *Param);
static std::string unparse(const URI &U);
+
+ friend bool operator==(const URI &LHS, const URI &RHS) {
+ return LHS.uri == RHS.uri;
+ }
+
+ friend bool operator!=(const URI &LHS, const URI &RHS) {
+ return !(LHS == RHS);
+ }
+
+ friend bool operator<(const URI &LHS, const URI &RHS) {
+ return LHS.uri < RHS.uri;
+ }
};
struct TextDocumentIdentifier {
@@ -86,6 +98,26 @@ struct Range {
static std::string unparse(const Range &P);
};
+struct Location {
+ /// The text document's URI.
+ URI uri;
+ Range range;
+
+ friend bool operator==(const Location &LHS, const Location &RHS) {
+ return LHS.uri == RHS.uri && LHS.range == RHS.range;
+ }
+
+ friend bool operator!=(const Location &LHS, const Location &RHS) {
+ return !(LHS == RHS);
+ }
+
+ friend bool operator<(const Location &LHS, const Location &RHS) {
+ return std::tie(LHS.uri, LHS.range) < std::tie(RHS.uri, RHS.range);
+ }
+
+ static std::string unparse(const Location &P);
+};
+
struct TextEdit {
/// The range of the text document to be manipulated. To insert
/// text into a document create a range where start === end.
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp Wed Jun 28 09:12:10 2017
@@ -186,6 +186,24 @@ private:
ProtocolCallbacks &Callbacks;
};
+struct GotoDefinitionHandler : Handler {
+ GotoDefinitionHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto TDPP = TextDocumentPositionParams::parse(Params);
+ if (!TDPP) {
+ Output.log("Failed to decode TextDocumentPositionParams!\n");
+ return;
+ }
+
+ Callbacks.onGoToDefinition(*TDPP, ID, Output);
+ }
+
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
} // namespace
void clangd::regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher,
@@ -219,4 +237,6 @@ void clangd::regiterCallbackHandlers(JSO
Dispatcher.registerHandler(
"textDocument/completion",
llvm::make_unique<CompletionHandler>(Out, Callbacks));
+ Dispatcher.registerHandler("textDocument/definition",
+ llvm::make_unique<GotoDefinitionHandler>(Out, Callbacks));
}
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.h?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.h (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h Wed Jun 28 09:12:10 2017
@@ -46,6 +46,8 @@ public:
JSONOutput &Out) = 0;
virtual void onCompletion(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) = 0;
+ virtual void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
+ JSONOutput &Out) = 0;
};
void regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,
Added: clang-tools-extra/trunk/test/clangd/definitions.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/definitions.test?rev=306558&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/definitions.test (added)
+++ clang-tools-extra/trunk/test/clangd/definitions.test Wed Jun 28 09:12:10 2017
@@ -0,0 +1,168 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+Content-Length: 172
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"int main() {\nint a;\na;\n}\n"}}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":0}}}
+# Go to local variable
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":1}}}
+# Go to local variable, end of token
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
+
+Content-Length: 214
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":2},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n Foo bar = { x : 1 };\n}\n"}]}}
+
+Content-Length: 149
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":14}}}
+# Go to field, GNU old-style field designator
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
+
+Content-Length: 215
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":3},"contentChanges":[{"text":"struct Foo {\nint x;\n};\nint main() {\n Foo baz = { .x = 2 };\n}\n"}]}}
+
+Content-Length: 149
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":15}}}
+# Go to field, field designator
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}]}
+
+Content-Length: 187
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":4},"contentChanges":[{"text":"int main() {\n main();\n return 0;\n}"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":3}}}
+# Go to function declaration, function call
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}]}
+
+Content-Length: 208
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"struct Foo {\n};\nint main() {\n Foo bar;\n return 0;\n}\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":3}}}
+# Go to struct declaration, new struct instance
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 1, "character": 1}}}]}
+
+Content-Length: 231
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":5},"contentChanges":[{"text":"namespace n1 {\nstruct Foo {\n};\n}\nint main() {\n n1::Foo bar;\n return 0;\n}\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":4}}}
+# Go to struct declaration, new struct instance, qualified name
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}]}
+
+Content-Length: 215
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":6},"contentChanges":[{"text":"struct Foo {\n int x;\n};\nint main() {\n Foo bar;\n bar.x;\n}\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
+# Go to field declaration, field reference
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1, "character": 7}}}]}
+
+Content-Length: 220
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n void x();\n};\nint main() {\n Foo bar;\n bar.x();\n}\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":5,"character":7}}}
+# Go to method declaration, method call
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 1, "character": 10}}}]}
+
+Content-Length: 240
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"struct Foo {\n};\ntypedef Foo TypedefFoo;\nint main() {\n TypedefFoo bar;\n return 0;\n}\n"}]}}
+
+Content-Length: 149
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":10}}}
+# Go to typedef
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 0}, "end": {"line": 2, "character": 22}}}]}
+
+Content-Length: 254
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"template <typename MyTemplateParam>\nvoid foo() {\n MyTemplateParam a;\n}\nint main() {\n return 0;\n}\n"}]}}
+
+Content-Length: 149
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":13}}}
+# Go to template type parameter. Fails until clangIndex is modified to handle those.
+# no-CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 10}, "end": {"line": 0, "character": 34}}}]}
+
+Content-Length: 256
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\nstatic void bar() {}\n};\n}\nint main() {\n ns::Foo::bar();\n return 0;\n}\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":6,"character":4}}}
+# Go to namespace, static method call
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 0}, "end": {"line": 4, "character": 1}}}]}
+
+Content-Length: 265
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"namespace ns {\nstruct Foo {\n int field;\n Foo(int param) : field(param) {}\n};\n}\nint main() {\n return 0;\n}\n"}]}}
+
+Content-Length: 149
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":21}}}
+# Go to field, member initializer
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 2}, "end": {"line": 2, "character": 11}}}]}
+
+Content-Length: 204
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define MY_MACRO 0\nint main() {\n return MY_MACRO;\n}\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":9}}}
+# Go to macro
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 18}}}]}
+
+Content-Length: 217
+
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":7},"contentChanges":[{"text":"#define FOO 1\nint a = FOO;\n#define FOO 2\nint b = FOO;\n#undef FOO\n"}]}}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":8}}}
+# Go to macro, re-defined later
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 13}}}]}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":8}}}
+# Go to macro, undefined later
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}
+
+Content-Length: 148
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":4,"character":7}}}
+# Go to macro, being undefined
+# CHECK: {"jsonrpc":"2.0","id":1,"result":[{"uri": "file:///main.cpp", "range": {"start": {"line": 2, "character": 8}, "end": {"line": 2, "character": 13}}}]}
+
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
Modified: clang-tools-extra/trunk/test/clangd/formatting.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/formatting.test?rev=306558&r1=306557&r2=306558&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/formatting.test (original)
+++ clang-tools-extra/trunk/test/clangd/formatting.test Wed Jun 28 09:12:10 2017
@@ -4,14 +4,15 @@
Content-Length: 125
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-# CHECK: Content-Length: 424
+# CHECK: Content-Length: 462
# CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
# CHECK: "textDocumentSync": 1,
# CHECK: "documentFormattingProvider": true,
# CHECK: "documentRangeFormattingProvider": true,
# CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
# CHECK: "codeActionProvider": true,
-# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]}
+# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]},
+# CHECK: "definitionProvider": true
# CHECK: }}}
#
Content-Length: 193
More information about the cfe-commits
mailing list