diff options
-rw-r--r-- | clang-tools-extra/clangd/CMakeLists.txt | 1 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ClangdLSPServer.cpp | 24 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ClangdServer.cpp | 14 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ClangdServer.h | 2 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ClangdUnit.cpp | 150 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ClangdUnit.h | 4 | ||||
-rw-r--r-- | clang-tools-extra/clangd/Protocol.cpp | 10 | ||||
-rw-r--r-- | clang-tools-extra/clangd/Protocol.h | 32 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ProtocolHandlers.cpp | 20 | ||||
-rw-r--r-- | clang-tools-extra/clangd/ProtocolHandlers.h | 2 | ||||
-rw-r--r-- | clang-tools-extra/test/clangd/definitions.test | 168 | ||||
-rw-r--r-- | clang-tools-extra/test/clangd/formatting.test | 5 |
12 files changed, 428 insertions, 4 deletions
diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt index f1c7098faf2..f5e70eed7b1 100644 --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -18,6 +18,7 @@ add_clang_library(clangDaemon clangBasic clangFormat clangFrontend + clangIndex clangSema clangTooling clangToolingCore diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index fde6b6fc4b3..1fd0e95aef4 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -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::LSPProtocolCallbacks::onInitialize(StringRef ID, "documentRangeFormattingProvider": true, "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]}, "codeActionProvider": true, - "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]} + "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]}, + "definitionProvider": true }}})"); } @@ -191,6 +194,25 @@ void ClangdLSPServer::LSPProtocolCallbacks::onCompletion( 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) {} diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 490780a42f3..5e668846229 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -271,3 +271,17 @@ std::string ClangdServer::dumpAST(PathRef File) { }); 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); +} diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index a8eba812540..8a2936f02df 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -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); diff --git a/clang-tools-extra/clangd/ClangdUnit.cpp b/clang-tools-extra/clangd/ClangdUnit.cpp index b1e0d4955d7..61bfe0bc25f 100644 --- a/clang-tools-extra/clangd/ClangdUnit.cpp +++ b/clang-tools-extra/clangd/ClangdUnit.cpp @@ -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::getLocalDiagnostics() const { 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; +} diff --git a/clang-tools-extra/clangd/ClangdUnit.h b/clang-tools-extra/clangd/ClangdUnit.h index 736a8e2bc48..81d1ba84ee3 100644 --- a/clang-tools-extra/clangd/ClangdUnit.h +++ b/clang-tools-extra/clangd/ClangdUnit.h @@ -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 diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index 016d8fd5f3f..17618f3a1c3 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -54,7 +54,7 @@ URI URI::parse(llvm::yaml::ScalarNode *Param) { } 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 &P) { 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; diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 8fd2ccc03c0..2e0c33d6d90 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -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. diff --git a/clang-tools-extra/clangd/ProtocolHandlers.cpp b/clang-tools-extra/clangd/ProtocolHandlers.cpp index 264ef33e297..b67ea0a8dc6 100644 --- a/clang-tools-extra/clangd/ProtocolHandlers.cpp +++ b/clang-tools-extra/clangd/ProtocolHandlers.cpp @@ -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(JSONRPCDispatcher &Dispatcher, Dispatcher.registerHandler( "textDocument/completion", llvm::make_unique<CompletionHandler>(Out, Callbacks)); + Dispatcher.registerHandler("textDocument/definition", + llvm::make_unique<GotoDefinitionHandler>(Out, Callbacks)); } diff --git a/clang-tools-extra/clangd/ProtocolHandlers.h b/clang-tools-extra/clangd/ProtocolHandlers.h index 2fb3db81bf3..0ee0383a4d2 100644 --- a/clang-tools-extra/clangd/ProtocolHandlers.h +++ b/clang-tools-extra/clangd/ProtocolHandlers.h @@ -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, diff --git a/clang-tools-extra/test/clangd/definitions.test b/clang-tools-extra/test/clangd/definitions.test new file mode 100644 index 00000000000..57e0dcecdc7 --- /dev/null +++ b/clang-tools-extra/test/clangd/definitions.test @@ -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"}
diff --git a/clang-tools-extra/test/clangd/formatting.test b/clang-tools-extra/test/clangd/formatting.test index d0a0cd50541..08be62937db 100644 --- a/clang-tools-extra/test/clangd/formatting.test +++ b/clang-tools-extra/test/clangd/formatting.test @@ -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
|