Index: clangd/ClangdLSPServer.cpp =================================================================== --- clangd/ClangdLSPServer.cpp +++ clangd/ClangdLSPServer.cpp @@ -275,16 +275,13 @@ } void ClangdLSPServer::onCompletion(TextDocumentPositionParams &Params) { - Server.codeComplete(Params.textDocument.uri.file, - Position{Params.position.line, Params.position.character}, - CCOpts, + Server.codeComplete(Params.textDocument.uri.file, Params.position, CCOpts, [](Tagged List) { reply(List.Value); }); } void ClangdLSPServer::onSignatureHelp(TextDocumentPositionParams &Params) { - auto SignatureHelp = Server.signatureHelp( - Params.textDocument.uri.file, - Position{Params.position.line, Params.position.character}); + auto SignatureHelp = + Server.signatureHelp(Params.textDocument.uri.file, Params.position); if (!SignatureHelp) return replyError(ErrorCode::InvalidParams, llvm::toString(SignatureHelp.takeError())); @@ -292,9 +289,8 @@ } void ClangdLSPServer::onGoToDefinition(TextDocumentPositionParams &Params) { - auto Items = Server.findDefinitions( - Params.textDocument.uri.file, - Position{Params.position.line, Params.position.character}); + auto Items = + Server.findDefinitions(Params.textDocument.uri.file, Params.position); if (!Items) return replyError(ErrorCode::InvalidParams, llvm::toString(Items.takeError())); @@ -307,9 +303,8 @@ } void ClangdLSPServer::onDocumentHighlight(TextDocumentPositionParams &Params) { - auto Highlights = Server.findDocumentHighlights( - Params.textDocument.uri.file, - Position{Params.position.line, Params.position.character}); + auto Highlights = Server.findDocumentHighlights(Params.textDocument.uri.file, + Params.position); if (!Highlights) { replyError(ErrorCode::InternalError, Index: clangd/ClangdUnit.cpp =================================================================== --- clangd/ClangdUnit.cpp +++ clangd/ClangdUnit.cpp @@ -136,10 +136,16 @@ // Note that clang also uses closed source ranges, which this can't handle! Range toRange(CharSourceRange R, const SourceManager &M) { // Clang is 1-based, LSP uses 0-based indexes. - return {{static_cast(M.getSpellingLineNumber(R.getBegin())) - 1, - static_cast(M.getSpellingColumnNumber(R.getBegin())) - 1}, - {static_cast(M.getSpellingLineNumber(R.getEnd())) - 1, - static_cast(M.getSpellingColumnNumber(R.getEnd())) - 1}}; + Position Begin; + Begin.line = static_cast(M.getSpellingLineNumber(R.getBegin())) - 1; + Begin.character = + static_cast(M.getSpellingColumnNumber(R.getBegin())) - 1; + + Position End; + End.line = static_cast(M.getSpellingLineNumber(R.getEnd())) - 1; + End.character = static_cast(M.getSpellingColumnNumber(R.getEnd())) - 1; + + return {Begin, End}; } // Clang diags have a location (shown as ^) and 0 or more ranges (~~~~). @@ -534,8 +540,11 @@ // 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 = getMacroArgExpandedLocation( - SourceMgr, FE, Position{Pos.line, Pos.character - 1}); + Position PosCharBehind = Pos; + --PosCharBehind.character; + + SourceLocation PeekBeforeLocation = + getMacroArgExpandedLocation(SourceMgr, FE, PosCharBehind); Token Result; if (Lexer::getRawToken(PeekBeforeLocation, Result, SourceMgr, AST.getLangOpts(), false)) { Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -78,10 +78,10 @@ struct Position { /// Line position in a document (zero-based). - int line; + int line = 0; /// Character offset on a line in a document (zero-based). - int character; + int character = 0; friend bool operator==(const Position &LHS, const Position &RHS) { return std::tie(LHS.line, LHS.character) == @@ -160,7 +160,7 @@ std::string languageId; /// The version number of this document (it will strictly increase after each - int version; + int version = 0; /// The content of the opened text document. std::string text; @@ -255,7 +255,7 @@ /// The file's URI. URIForFile uri; /// The change type. - FileChangeType type; + FileChangeType type = FileChangeType::Created; }; bool fromJSON(const json::Expr &, FileEvent &); @@ -267,10 +267,10 @@ struct FormattingOptions { /// Size of a tab in spaces. - int tabSize; + int tabSize = 0; /// Prefer spaces over tabs. - bool insertSpaces; + bool insertSpaces = false; }; bool fromJSON(const json::Expr &, FormattingOptions &); json::Expr toJSON(const FormattingOptions &); @@ -317,7 +317,7 @@ /// The diagnostic's severity. Can be omitted. If omitted it is up to the /// client to interpret diagnostics as error, warning, info or hint. - int severity; + int severity = 0; /// The diagnostic's code. Can be omitted. /// Note: Not currently used by clangd @@ -388,7 +388,6 @@ std::string command; // Arguments - llvm::Optional workspaceEdit; }; bool fromJSON(const json::Expr &, ExecuteCommandParams &); @@ -453,10 +452,13 @@ /// user keeps typing. /// This is a clangd extension. struct CompletionItemScores { - float finalScore; /// The score that items are ranked by. - /// This is filterScore * symbolScore. - float filterScore; /// How the partial identifier matched filterText. [0-1] - float symbolScore; /// How the symbol fits, ignoring the partial identifier. + /// The score that items are ranked by. + /// This is filterScore * symbolScore. + float finalScore = 0.f; + /// How the partial identifier matched filterText. [0-1] + float filterScore = 0.f; + /// How the symbol fits, ignoring the partial identifier. + float symbolScore = 0.f; }; struct CompletionItem { @@ -588,13 +590,10 @@ /// the background color of its range. struct DocumentHighlight { - /// The range this highlight applies to. - Range range; /// The highlight kind, default is DocumentHighlightKind.Text. - DocumentHighlightKind kind = DocumentHighlightKind::Text; friend bool operator<(const DocumentHighlight &LHS, Index: clangd/SourceCode.cpp =================================================================== --- clangd/SourceCode.cpp +++ clangd/SourceCode.cpp @@ -33,7 +33,10 @@ size_t PrevNL = Before.rfind('\n'); size_t StartOfLine = (PrevNL == StringRef::npos) ? 0 : (PrevNL + 1); // FIXME: officially character counts UTF-16 code units, not UTF-8 bytes! - return {Lines, static_cast(Offset - StartOfLine)}; + Position Pos; + Pos.line = Lines; + Pos.character = static_cast(Offset - StartOfLine); + return Pos; } } // namespace clangd Index: unittests/clangd/ClangdTests.cpp =================================================================== --- unittests/clangd/ClangdTests.cpp +++ unittests/clangd/ClangdTests.cpp @@ -280,15 +280,13 @@ // thread. FS.Tag = "123"; Server.addDocument(FooCpp, SourceContents); - EXPECT_EQ(runCodeComplete(Server, FooCpp, Position{0, 0}, CCOpts).Tag, - FS.Tag); + EXPECT_EQ(runCodeComplete(Server, FooCpp, Position(), CCOpts).Tag, FS.Tag); EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag); FS.Tag = "321"; Server.addDocument(FooCpp, SourceContents); EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag); - EXPECT_EQ(runCodeComplete(Server, FooCpp, Position{0, 0}, CCOpts).Tag, - FS.Tag); + EXPECT_EQ(runCodeComplete(Server, FooCpp, Position(), CCOpts).Tag, FS.Tag); } // Only enable this test on Unix @@ -451,16 +449,16 @@ Server.addDocument(FooCpp, "int main() {}"); EXPECT_EQ(Server.dumpAST(FooCpp), ""); - EXPECT_ERROR(Server.findDefinitions(FooCpp, Position{0, 0})); - EXPECT_ERROR(Server.findDocumentHighlights(FooCpp, Position{0, 0})); - EXPECT_ERROR(Server.rename(FooCpp, Position{0, 0}, "new_name")); + EXPECT_ERROR(Server.findDefinitions(FooCpp, Position())); + EXPECT_ERROR(Server.findDocumentHighlights(FooCpp, Position())); + EXPECT_ERROR(Server.rename(FooCpp, Position(), "new_name")); // FIXME: codeComplete and signatureHelp should also return errors when they // can't parse the file. - EXPECT_THAT(runCodeComplete(Server, FooCpp, Position{0, 0}, - clangd::CodeCompleteOptions()) - .Value.items, - IsEmpty()); - auto SigHelp = Server.signatureHelp(FooCpp, Position{0, 0}); + EXPECT_THAT( + runCodeComplete(Server, FooCpp, Position(), clangd::CodeCompleteOptions()) + .Value.items, + IsEmpty()); + auto SigHelp = Server.signatureHelp(FooCpp, Position()); ASSERT_TRUE(bool(SigHelp)) << "signatureHelp returned an error"; EXPECT_THAT(SigHelp->Value.signatures, IsEmpty()); } @@ -642,7 +640,9 @@ if (ReqStats[FileIndex].FileIsRemoved) AddDocument(FileIndex); - Position Pos{LineDist(RandGen), ColumnDist(RandGen)}; + Position Pos; + Pos.line = LineDist(RandGen); + Pos.character = ColumnDist(RandGen); // FIXME(ibiryukov): Also test async completion requests. // Simply putting CodeCompletion into async requests now would make // tests slow, since there's no way to cancel previous completion @@ -659,7 +659,10 @@ if (ReqStats[FileIndex].FileIsRemoved) AddDocument(FileIndex); - Position Pos{LineDist(RandGen), ColumnDist(RandGen)}; + Position Pos; + Pos.line = LineDist(RandGen); + Pos.character = ColumnDist(RandGen); + ASSERT_TRUE(!!Server.findDefinitions(FilePaths[FileIndex], Pos)); }; Index: unittests/clangd/SourceCodeTests.cpp =================================================================== --- unittests/clangd/SourceCodeTests.cpp +++ unittests/clangd/SourceCodeTests.cpp @@ -23,32 +23,40 @@ 1:0 = 8 2:0 = 16)"; +/// A helper to make tests easier to read. +Position position(int line, int character) { + Position Pos; + Pos.line = line; + Pos.character = character; + return Pos; +} + TEST(SourceCodeTests, PositionToOffset) { // line out of bounds - EXPECT_EQ(0u, positionToOffset(File, Position{-1, 2})); + EXPECT_EQ(0u, positionToOffset(File, position(-1, 2))); // first line - EXPECT_EQ(0u, positionToOffset(File, Position{0, -1})); // out of range - EXPECT_EQ(0u, positionToOffset(File, Position{0, 0})); // first character - EXPECT_EQ(3u, positionToOffset(File, Position{0, 3})); // middle character - EXPECT_EQ(6u, positionToOffset(File, Position{0, 6})); // last character - EXPECT_EQ(7u, positionToOffset(File, Position{0, 7})); // the newline itself - EXPECT_EQ(8u, positionToOffset(File, Position{0, 8})); // out of range + EXPECT_EQ(0u, positionToOffset(File, position(0, -1))); // out of range + EXPECT_EQ(0u, positionToOffset(File, position(0, 0))); // first character + EXPECT_EQ(3u, positionToOffset(File, position(0, 3))); // middle character + EXPECT_EQ(6u, positionToOffset(File, position(0, 6))); // last character + EXPECT_EQ(7u, positionToOffset(File, position(0, 7))); // the newline itself + EXPECT_EQ(8u, positionToOffset(File, position(0, 8))); // out of range // middle line - EXPECT_EQ(8u, positionToOffset(File, Position{1, -1})); // out of range - EXPECT_EQ(8u, positionToOffset(File, Position{1, 0})); // first character - EXPECT_EQ(11u, positionToOffset(File, Position{1, 3})); // middle character - EXPECT_EQ(14u, positionToOffset(File, Position{1, 6})); // last character - EXPECT_EQ(15u, positionToOffset(File, Position{1, 7})); // the newline itself - EXPECT_EQ(16u, positionToOffset(File, Position{1, 8})); // out of range + EXPECT_EQ(8u, positionToOffset(File, position(1, -1))); // out of range + EXPECT_EQ(8u, positionToOffset(File, position(1, 0))); // first character + EXPECT_EQ(11u, positionToOffset(File, position(1, 3))); // middle character + EXPECT_EQ(14u, positionToOffset(File, position(1, 6))); // last character + EXPECT_EQ(15u, positionToOffset(File, position(1, 7))); // the newline itself + EXPECT_EQ(16u, positionToOffset(File, position(1, 8))); // out of range // last line - EXPECT_EQ(16u, positionToOffset(File, Position{2, -1})); // out of range - EXPECT_EQ(16u, positionToOffset(File, Position{2, 0})); // first character - EXPECT_EQ(19u, positionToOffset(File, Position{2, 3})); // middle character - EXPECT_EQ(23u, positionToOffset(File, Position{2, 7})); // last character - EXPECT_EQ(24u, positionToOffset(File, Position{2, 8})); // EOF - EXPECT_EQ(24u, positionToOffset(File, Position{2, 9})); // out of range + EXPECT_EQ(16u, positionToOffset(File, position(2, -1))); // out of range + EXPECT_EQ(16u, positionToOffset(File, position(2, 0))); // first character + EXPECT_EQ(19u, positionToOffset(File, position(2, 3))); // middle character + EXPECT_EQ(23u, positionToOffset(File, position(2, 7))); // last character + EXPECT_EQ(24u, positionToOffset(File, position(2, 8))); // EOF + EXPECT_EQ(24u, positionToOffset(File, position(2, 9))); // out of range // line out of bounds - EXPECT_EQ(24u, positionToOffset(File, Position{3, 1})); + EXPECT_EQ(24u, positionToOffset(File, position(3, 1))); } TEST(SourceCodeTests, OffsetToPosition) {