diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp --- a/clang/lib/Tooling/Transformer/Stencil.cpp +++ b/clang/lib/Tooling/Transformer/Stencil.cpp @@ -323,10 +323,23 @@ return llvm::make_error(errc::invalid_argument, "Id not bound: " + Data.BaseId); if (!E->isImplicitCXXThis()) { - if (llvm::Optional S = - E->getType()->isAnyPointerType() - ? tooling::buildArrow(*E, *Match.Context) - : tooling::buildDot(*E, *Match.Context)) + llvm::Optional S; + if (E->getType()->isAnyPointerType() || + isSmartPointerType(E->getType(), *Match.Context)) { + // Strip off any operator->. This can only occur inside an actual arrow + // member access, so we treat it as equivalent to an actual object + // expression. + if (const auto *OpCall = dyn_cast(E)) { + if (OpCall->getOperator() == clang::OO_Arrow && + OpCall->getNumArgs() == 1) { + E = OpCall->getArg(0); + } + } + S = tooling::buildArrow(*E, *Match.Context); + } else { + S = tooling::buildDot(*E, *Match.Context); + } + if (S.hasValue()) *Result += *S; else return llvm::make_error( diff --git a/clang/unittests/Tooling/StencilTest.cpp b/clang/unittests/Tooling/StencilTest.cpp --- a/clang/unittests/Tooling/StencilTest.cpp +++ b/clang/unittests/Tooling/StencilTest.cpp @@ -392,6 +392,37 @@ testExpr(Id, Snippet, access(Id, "field"), "x->field"); } +TEST_F(StencilTest, AccessOpSmartPointer) { + StringRef Snippet = R"cc( + Smart x; + x; + )cc"; + StringRef Id = "id"; + testExpr(Id, Snippet, access(Id, "field"), "x->field"); +} + +TEST_F(StencilTest, AccessOpSmartPointerDereference) { + StringRef Snippet = R"cc( + Smart x; + *x; + )cc"; + StringRef Id = "id"; + testExpr(Id, Snippet, access(Id, "field"), "(*x).field"); +} + +TEST_F(StencilTest, AccessOpSmartPointerMemberCall) { + StringRef Snippet = R"cc( + Smart x; + x->Field; + )cc"; + StringRef Id = "id"; + auto StmtMatch = + matchStmt(Snippet, memberExpr(hasObjectExpression(expr().bind(Id)))); + ASSERT_TRUE(StmtMatch); + EXPECT_THAT_EXPECTED(access(Id, "field")->eval(StmtMatch->Result), + HasValue("x->field")); +} + TEST_F(StencilTest, AccessOpExplicitThis) { using clang::ast_matchers::hasObjectExpression; using clang::ast_matchers::memberExpr;