kadircet created this revision. kadircet added a reviewer: sammccall. Herald added subscribers: usaxena95, arphaman. kadircet requested review of this revision. Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov. Herald added a project: clang-tools-extra.
References to fields inside anon structs contain an implicit children for the container, which has the same SourceLocation with the field. This was resulting in SelectionTree always picking the anon-struct rather than the field as the selection. This patch prevents that by claiming the range for the field early. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D110825 Files: clang-tools-extra/clangd/Selection.cpp clang-tools-extra/clangd/unittests/XRefsTests.cpp Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -365,6 +365,25 @@ ElementsAre(Sym("Forward", SymbolHeader.range("forward"), Test.range()))); } +TEST(LocateSymbol, AnonymousStructFields) { + auto Code = Annotations(R"cpp( + class Foo { + struct { + struct { + int $1[[x]]; + } $0[[y]]; + }; + void foo() { $0^y.$1^x = 2; } + }; + )cpp"); + TestTU TU = TestTU::withCode(Code.code()); + auto AST = TU.build(); + EXPECT_THAT(locateSymbolAt(AST, Code.point("0"), TU.index().get()), + UnorderedElementsAre(Sym("y", Code.range("0"), Code.range("0")))); + EXPECT_THAT(locateSymbolAt(AST, Code.point("1"), TU.index().get()), + UnorderedElementsAre(Sym("x", Code.range("1"), Code.range("1")))); +} + TEST(LocateSymbol, FindOverrides) { auto Code = Annotations(R"cpp( class Foo { Index: clang-tools-extra/clangd/Selection.cpp =================================================================== --- clang-tools-extra/clangd/Selection.cpp +++ clang-tools-extra/clangd/Selection.cpp @@ -732,6 +732,19 @@ } else if (const auto *CCI = N.get<CXXCtorInitializer>()) { // : [[b_]](42) return CCI->getMemberLocation(); + } else if (const auto *ME = N.get<MemberExpr>()) { + // In member expressions involving anonymous structs, there's an implicit + // reference to the container. Make sure all the tokens that belong to the + // member are claimed first to prevent this unspelled children from owning + // them. + // struct Foo { + // struct { int x; } + // void foo() { [[x]] = 2; } + // }; + if (auto *FD = llvm::dyn_cast<FieldDecl>(ME->getMemberDecl())) { + if (FD->getParent()->isAnonymousStructOrUnion()) + return SourceRange(ME->getMemberLoc(), ME->getEndLoc()); + } } return SourceRange(); }
Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp =================================================================== --- clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -365,6 +365,25 @@ ElementsAre(Sym("Forward", SymbolHeader.range("forward"), Test.range()))); } +TEST(LocateSymbol, AnonymousStructFields) { + auto Code = Annotations(R"cpp( + class Foo { + struct { + struct { + int $1[[x]]; + } $0[[y]]; + }; + void foo() { $0^y.$1^x = 2; } + }; + )cpp"); + TestTU TU = TestTU::withCode(Code.code()); + auto AST = TU.build(); + EXPECT_THAT(locateSymbolAt(AST, Code.point("0"), TU.index().get()), + UnorderedElementsAre(Sym("y", Code.range("0"), Code.range("0")))); + EXPECT_THAT(locateSymbolAt(AST, Code.point("1"), TU.index().get()), + UnorderedElementsAre(Sym("x", Code.range("1"), Code.range("1")))); +} + TEST(LocateSymbol, FindOverrides) { auto Code = Annotations(R"cpp( class Foo { Index: clang-tools-extra/clangd/Selection.cpp =================================================================== --- clang-tools-extra/clangd/Selection.cpp +++ clang-tools-extra/clangd/Selection.cpp @@ -732,6 +732,19 @@ } else if (const auto *CCI = N.get<CXXCtorInitializer>()) { // : [[b_]](42) return CCI->getMemberLocation(); + } else if (const auto *ME = N.get<MemberExpr>()) { + // In member expressions involving anonymous structs, there's an implicit + // reference to the container. Make sure all the tokens that belong to the + // member are claimed first to prevent this unspelled children from owning + // them. + // struct Foo { + // struct { int x; } + // void foo() { [[x]] = 2; } + // }; + if (auto *FD = llvm::dyn_cast<FieldDecl>(ME->getMemberDecl())) { + if (FD->getParent()->isAnonymousStructOrUnion()) + return SourceRange(ME->getMemberLoc(), ME->getEndLoc()); + } } return SourceRange(); }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits