Index: clangd/index/Index.h =================================================================== --- clangd/index/Index.h +++ clangd/index/Index.h @@ -24,13 +24,26 @@ namespace clangd { struct SymbolLocation { + struct Position { + // Line position in a document (zero-based). + int Line = 0; + + // Character offset on a line in a document (zero-based). + int Character = 0; + }; + // The URI of the source file where a symbol occurs. llvm::StringRef FileURI; // The 0-based offsets of the symbol from the beginning of the source file, // using half-open range, [StartOffset, EndOffset). + // FIXME(hokein): remove these fields in favor of Position. unsigned StartOffset = 0; unsigned EndOffset = 0; + /// The symbol range, using half-open range [StartPos, EndPos). + Position StartPos; + Position EndPos; + operator bool() const { return !FileURI.empty(); } }; llvm::raw_ostream &operator<<(llvm::raw_ostream &, const SymbolLocation &); Index: clangd/index/SymbolCollector.cpp =================================================================== --- clangd/index/SymbolCollector.cpp +++ clangd/index/SymbolCollector.cpp @@ -193,8 +193,18 @@ SymbolLocation Result; Result.FileURI = FileURIStorage; Result.StartOffset = SM.getFileOffset(NameLoc); - Result.EndOffset = Result.StartOffset + clang::Lexer::MeasureTokenLength( - NameLoc, SM, LangOpts); + auto TokenLength = clang::Lexer::MeasureTokenLength(NameLoc, SM, LangOpts); + Result.EndOffset = Result.StartOffset + TokenLength; + + auto FileIdAndOffset = SM.getDecomposedLoc(NameLoc); + auto FileId = FileIdAndOffset.first; + auto Offset = FileIdAndOffset.second; + // LSP is 0-based while source location is 1-based. + Result.StartPos.Line = SM.getLineNumber(FileId, Offset) - 1; + Result.StartPos.Character = SM.getColumnNumber(FileId, Offset) - 1; + Result.EndPos.Line = Result.StartPos.Line; + Result.EndPos.Character = Result.StartPos.Character + TokenLength; + return std::move(Result); } Index: clangd/index/SymbolYAML.cpp =================================================================== --- clangd/index/SymbolYAML.cpp +++ clangd/index/SymbolYAML.cpp @@ -43,11 +43,20 @@ std::string HexString; }; +template <> struct MappingTraits { + static void mapping(IO &io, SymbolLocation::Position &Pos) { + io.mapRequired("line", Pos.Line); + io.mapRequired("character", Pos.Character); + } +}; + template <> struct MappingTraits { static void mapping(IO &IO, SymbolLocation &Value) { IO.mapRequired("StartOffset", Value.StartOffset); IO.mapRequired("EndOffset", Value.EndOffset); IO.mapRequired("FileURI", Value.FileURI); + IO.mapRequired("StartPos", Value.StartPos); + IO.mapRequired("EndPos", Value.EndPos); } }; Index: unittests/clangd/SymbolCollectorTests.cpp =================================================================== --- unittests/clangd/SymbolCollectorTests.cpp +++ unittests/clangd/SymbolCollectorTests.cpp @@ -59,6 +59,21 @@ return arg.Definition.StartOffset == Offsets.first && arg.Definition.EndOffset == Offsets.second; } +MATCHER_P(DeclRangePos, Pos, "") { + return std::tie(arg.CanonicalDeclaration.StartPos.Line, + arg.CanonicalDeclaration.StartPos.Character, + arg.CanonicalDeclaration.EndPos.Line, + arg.CanonicalDeclaration.EndPos.Character) == + std::tie(Pos.start.line, Pos.start.character, Pos.end.line, + Pos.end.character); +} +MATCHER_P(DefRangePos, Pos, "") { + return std::tie(arg.Definition.StartPos.Line, + arg.Definition.StartPos.Character, arg.Definition.EndPos.Line, + arg.Definition.EndPos.Character) == + std::tie(Pos.start.line, Pos.start.character, Pos.end.line, + Pos.end.character); +} MATCHER_P(Refs, R, "") { return int(arg.References) == R; } namespace clang { @@ -209,7 +224,8 @@ )"); runSymbolCollector(Header.code(), /*Main=*/""); EXPECT_THAT(Symbols, UnorderedElementsAreArray({AllOf( - QName("Tmpl"), DeclRange(Header.offsetRange()))})); + QName("Tmpl"), DeclRange(Header.offsetRange()), + DeclRangePos(Header.range()))})); } TEST_F(SymbolCollectorTest, Locations) { @@ -234,13 +250,24 @@ EXPECT_THAT( Symbols, UnorderedElementsAre( - AllOf(QName("X"), DeclRange(Header.offsetRange("xdecl")), - DefRange(Main.offsetRange("xdef"))), - AllOf(QName("Cls"), DeclRange(Header.offsetRange("clsdecl")), - DefRange(Main.offsetRange("clsdef"))), - AllOf(QName("print"), DeclRange(Header.offsetRange("printdecl")), - DefRange(Main.offsetRange("printdef"))), - AllOf(QName("Z"), DeclRange(Header.offsetRange("zdecl"))))); + AllOf(QName("X"), + DeclRange(Header.offsetRange("xdecl")), + DeclRangePos(Header.range("xdecl")), + DefRange(Main.offsetRange("xdef")), + DefRangePos(Main.range("xdef"))), + AllOf(QName("Cls"), + DeclRange(Header.offsetRange("clsdecl")), + DeclRangePos(Header.range("clsdecl")), + DefRange(Main.offsetRange("clsdef")), + DefRangePos(Main.range("clsdef"))), + AllOf(QName("print"), + DeclRange(Header.offsetRange("printdecl")), + DeclRangePos(Header.range("printdecl")), + DefRange(Main.offsetRange("printdef")), + DefRangePos(Main.range("printdef"))), + AllOf(QName("Z"), + DeclRange(Header.offsetRange("zdecl")), + DeclRangePos(Header.range("zdecl"))))); } TEST_F(SymbolCollectorTest, References) { @@ -365,9 +392,13 @@ EXPECT_THAT( Symbols, UnorderedElementsAre( - AllOf(QName("abc_Test"), DeclRange(Header.offsetRange("expansion")), + AllOf(QName("abc_Test"), + DeclRange(Header.offsetRange("expansion")), + DeclRangePos(Header.range("expansion")), DeclURI(TestHeaderURI)), - AllOf(QName("Test"), DeclRange(Header.offsetRange("spelling")), + AllOf(QName("Test"), + DeclRange(Header.offsetRange("spelling")), + DeclRangePos(Header.range("spelling")), DeclURI(TestHeaderURI)))); } @@ -382,7 +413,9 @@ /*ExtraArgs=*/{"-DNAME=name"}); EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf( - QName("name"), DeclRange(Header.offsetRange("expansion")), + QName("name"), + DeclRange(Header.offsetRange("expansion")), + DeclRangePos(Header.range("expansion")), DeclURI(TestHeaderURI)))); } @@ -514,6 +547,12 @@ StartOffset: 0 EndOffset: 1 FileURI: file:///path/foo.h + StartPos: + line: 0 + character: 0 + EndPos: + line: 0 + character: 1 CompletionLabel: 'Foo1-label' CompletionFilterText: 'filter' CompletionPlainInsertText: 'plain' @@ -534,6 +573,12 @@ StartOffset: 10 EndOffset: 12 FileURI: file:///path/bar.h + StartPos: + line: 0 + character: 0 + EndPos: + line: 0 + character: 1 CompletionLabel: 'Foo2-label' CompletionFilterText: 'filter' CompletionPlainInsertText: 'plain'