scw created this revision. scw requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This extends smart pointer support beyond the existing `maybeDeref` and `maybeAddressOf`. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D100450 Files: clang/lib/Tooling/Transformer/Stencil.cpp clang/unittests/Tooling/StencilTest.cpp Index: clang/unittests/Tooling/StencilTest.cpp =================================================================== --- clang/unittests/Tooling/StencilTest.cpp +++ 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; Index: clang/lib/Tooling/Transformer/Stencil.cpp =================================================================== --- clang/lib/Tooling/Transformer/Stencil.cpp +++ clang/lib/Tooling/Transformer/Stencil.cpp @@ -323,10 +323,23 @@ return llvm::make_error<StringError>(errc::invalid_argument, "Id not bound: " + Data.BaseId); if (!E->isImplicitCXXThis()) { - if (llvm::Optional<std::string> S = - E->getType()->isAnyPointerType() - ? tooling::buildArrow(*E, *Match.Context) - : tooling::buildDot(*E, *Match.Context)) + llvm::Optional<std::string> 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<clang::CXXOperatorCallExpr>(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<StringError>(
Index: clang/unittests/Tooling/StencilTest.cpp =================================================================== --- clang/unittests/Tooling/StencilTest.cpp +++ 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; Index: clang/lib/Tooling/Transformer/Stencil.cpp =================================================================== --- clang/lib/Tooling/Transformer/Stencil.cpp +++ clang/lib/Tooling/Transformer/Stencil.cpp @@ -323,10 +323,23 @@ return llvm::make_error<StringError>(errc::invalid_argument, "Id not bound: " + Data.BaseId); if (!E->isImplicitCXXThis()) { - if (llvm::Optional<std::string> S = - E->getType()->isAnyPointerType() - ? tooling::buildArrow(*E, *Match.Context) - : tooling::buildDot(*E, *Match.Context)) + llvm::Optional<std::string> 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<clang::CXXOperatorCallExpr>(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<StringError>(
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits