if (auto *CTI = llvm::dyn_cast<CXXThisExpr>(S))
if (CTI->isImplicit())
return true;
+ // Make sure implicit access of anonymous structs don't end up owning tokens.
+ if (auto *ME = llvm::dyn_cast<MemberExpr>(S)) {
+ if (auto *FD = llvm::dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (FD->isAnonymousStructOrUnion())
+ // If Base is an implicit CXXThis, then the whole MemberExpr has no
+ // tokens. If it's a normal e.g. DeclRef, we treat the MemberExpr like
+ // an implicit cast.
+ return isImplicit(ME->getBase());
+ }
// Refs to operator() and [] are (almost?) always implicit as part of calls.
if (auto *DRE = llvm::dyn_cast<DeclRefExpr>(S)) {
if (auto *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl())) {
ElementsAre(Sym("Forward", SymbolHeader.range("forward"), Test.range())));
}
+TEST(LocateSymbol, AnonymousStructFields) {
+ auto Code = Annotations(R"cpp(
+ struct $2[[Foo]] {
+ struct { int $1[[x]]; };
+ void foo() {
+ // Make sure the implicit base is skipped.
+ $1^x = 42;
+ }
+ };
+ // Check that we don't skip explicit bases.
+ int a = $2^Foo{}.x;
+ )cpp");
+ TestTU TU = TestTU::withCode(Code.code());
+ auto AST = TU.build();
+ EXPECT_THAT(locateSymbolAt(AST, Code.point("1"), TU.index().get()),
+ UnorderedElementsAre(Sym("x", Code.range("1"), Code.range("1"))));
+ EXPECT_THAT(
+ locateSymbolAt(AST, Code.point("2"), TU.index().get()),
+ UnorderedElementsAre(Sym("Foo", Code.range("2"), Code.range("2"))));
+}
+
TEST(LocateSymbol, FindOverrides) {
auto Code = Annotations(R"cpp(
class Foo {