diff --git a/clang/include/clang/Tooling/Transformer/Stencil.h b/clang/include/clang/Tooling/Transformer/Stencil.h --- a/clang/include/clang/Tooling/Transformer/Stencil.h +++ b/clang/include/clang/Tooling/Transformer/Stencil.h @@ -92,6 +92,14 @@ /// needed. Stencil addressOf(llvm::StringRef ExprId); +// Constructs an expression that idiomatically represents a value, taking into +// account whether `ExprId` is a pointer or already a value. +Stencil asValue(llvm::StringRef ExprId); + +// Constructs an expression that idiomatically represents a pointer, taking into +// account whether `ExprId` is a value or already a pointer. +Stencil asPointer(llvm::StringRef ExprId); + /// Constructs a `MemberExpr` that accesses the named member (\p Member) of the /// object bound to \p BaseId. The access is constructed idiomatically: if \p /// BaseId is bound to `e` and \p Member identifies member `m`, then returns 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 @@ -60,6 +60,8 @@ Parens, Deref, Address, + AsValue, + AsPointer, }; // Generic container for stencil operations with a (single) node-id argument. @@ -124,6 +126,12 @@ case UnaryNodeOperator::Address: OpName = "addressOf"; break; + case UnaryNodeOperator::AsValue: + OpName = "asValue"; + break; + case UnaryNodeOperator::AsPointer: + OpName = "asPointer"; + break; } return (OpName + "(\"" + Data.Id + "\")").str(); } @@ -194,6 +202,21 @@ case UnaryNodeOperator::Address: Source = tooling::buildAddressOf(*E, *Match.Context); break; + case UnaryNodeOperator::AsValue: + if (!E->getType()->isAnyPointerType()) { + *Result += tooling::getText(*E, *Match.Context); + return Error::success(); + } + Source = tooling::buildDereference(*E, *Match.Context); + break; + + case UnaryNodeOperator::AsPointer: + if (E->getType()->isAnyPointerType()) { + *Result += tooling::getText(*E, *Match.Context); + return Error::success(); + } + Source = tooling::buildAddressOf(*E, *Match.Context); + break; } if (!Source) return llvm::make_error( @@ -305,6 +328,16 @@ UnaryNodeOperator::Address, ExprId); } +Stencil transformer::asValue(llvm::StringRef ExprId) { + return std::make_shared>( + UnaryNodeOperator::AsValue, ExprId); +} + +Stencil transformer::asPointer(llvm::StringRef ExprId) { + return std::make_shared>( + UnaryNodeOperator::AsPointer, ExprId); +} + Stencil transformer::access(StringRef BaseId, Stencil Member) { return std::make_shared>(BaseId, std::move(Member)); } 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 @@ -233,6 +233,46 @@ testExpr(Id, "int *x; *x;", addressOf(Id), "x"); } +TEST_F(StencilTest, AsValueValue) { + StringRef Id = "id"; + testExpr(Id, "int x; x;", asValue(Id), "x"); +} + +TEST_F(StencilTest, AsValuePointer) { + StringRef Id = "id"; + testExpr(Id, "int *x; x;", asValue(Id), "*x"); +} + +TEST_F(StencilTest, AsValueBinOp) { + StringRef Id = "id"; + testExpr(Id, "int *x; x + 1;", asValue(Id), "*(x + 1)"); +} + +TEST_F(StencilTest, AsValueAddressExpr) { + StringRef Id = "id"; + testExpr(Id, "int x; &x;", asValue(Id), "x"); +} + +TEST_F(StencilTest, AsPointerPointer) { + StringRef Id = "id"; + testExpr(Id, "int *x; x;", asPointer(Id), "x"); +} + +TEST_F(StencilTest, AsPointerValue) { + StringRef Id = "id"; + testExpr(Id, "int x; x;", addressOf(Id), "&x"); +} + +TEST_F(StencilTest, AsPointerBinOp) { + StringRef Id = "id"; + testExpr(Id, "int x; x + 1;", asPointer(Id), "&(x + 1)"); +} + +TEST_F(StencilTest, AsPointerDerefExpr) { + StringRef Id = "id"; + testExpr(Id, "int *x; *x;", addressOf(Id), "x"); +} + TEST_F(StencilTest, AccessOpValue) { StringRef Snippet = R"cc( S x;