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 @@ -73,6 +73,25 @@ return match(SmartPointer, Ty, Context).size() > 0; } +static const Expr *isDereference(const Expr &E, ASTContext &Context) { + using namespace ::clang::ast_matchers; + + const auto HasOverloadedArrow = cxxRecordDecl(hasMethod(cxxMethodDecl( + hasOverloadedOperatorName("->"), returns(qualType(pointsTo(type())))))); + auto Deref = expr(anyOf( + cxxOperatorCallExpr(hasOverloadedOperatorName("*"), + // FIXME: Use `hasUnaryOperand` once bug in + // `equivalentUnaryOperand` is fixed. + // hasArgument(0, expr().bind("arg")) + hasUnaryOperand(expr().bind("arg")), + callee(cxxMethodDecl(ofClass(HasOverloadedArrow)))), + unaryOperator(hasOperatorName("*"), + hasUnaryOperand(expr().bind("arg"))))); + auto matches = match(Deref, E, Context); + llvm::errs() << "num matches = " << matches.size() << "\n"; + return selectFirst("arg", matches); +} + namespace { // An arbitrary fragment of code within a stencil. class RawTextStencil : public StencilInterface { @@ -309,6 +328,8 @@ } } S = tooling::buildArrow(*E, *Match.Context); + } else if (const auto *Operand = isDereference(*E, *Match.Context)) { + S = tooling::buildArrow(*Operand, *Match.Context); } else { S = tooling::buildDot(*E, *Match.Context); } 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 @@ -407,7 +407,7 @@ *x; )cc"; StringRef Id = "id"; - testExpr(Id, Snippet, access(Id, "field"), "(*x).field"); + testExpr(Id, Snippet, access(Id, "field"), "x->field"); } TEST_F(StencilTest, AccessOpSmartPointerMemberCall) {