return (llvm::Twine("*") + Text).str();
}
-// Trying to get CallExpr in which CxxConstructExpr is called.
-static const clang::CallExpr *
-tryGetCallExprAncestorForCxxConstructExpr(const Expr *TheExpr,
- ASTContext &Context) {
- // We skip nodes such as CXXBindTemporaryExpr, MaterializeTemporaryExpr.
- for (ast_type_traits::DynTypedNode DynParent : Context.getParents(*TheExpr)) {
- if (const auto *Parent = DynParent.get<Expr>()) {
- if (const auto *TheCallExpr = dyn_cast<CallExpr>(Parent))
- return TheCallExpr;
-
- if (const clang::CallExpr *TheCallExpr =
- tryGetCallExprAncestorForCxxConstructExpr(Parent, Context))
- return TheCallExpr;
- }
- }
-
- return nullptr;
-}
-
-// Check that ParamDecl of CallExprDecl has rvalue type.
-static bool checkParamDeclOfAncestorCallExprHasRValueRefType(
- const Expr *TheCxxConstructExpr, ASTContext &Context) {
- if (const clang::CallExpr *TheCallExpr =
- tryGetCallExprAncestorForCxxConstructExpr(TheCxxConstructExpr,
- Context)) {
- for (unsigned i = 0; i < TheCallExpr->getNumArgs(); ++i) {
- const Expr *Arg = TheCallExpr->getArg(i);
- if (Arg->getSourceRange() == TheCxxConstructExpr->getSourceRange()) {
- if (const auto *TheCallExprFuncProto =
- TheCallExpr->getCallee()
- ->getType()
- ->getPointeeType()
- ->getAs<FunctionProtoType>()) {
- if (TheCallExprFuncProto->getParamType(i)->isRValueReferenceType())
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
-AST_MATCHER(CXXConstructExpr,
- matchedParamDeclOfAncestorCallExprHasRValueRefType) {
- return checkParamDeclOfAncestorCallExprHasRValueRefType(
- &Node, Finder->getASTContext());
+AST_MATCHER(MaterializeTemporaryExpr, isBoundToLValue) {
+ return Node.isBoundToLvalueReference();
}
} // end namespace
// Detect redundant 'c_str()' calls through a string constructor.
// If CxxConstructExpr is the part of some CallExpr we need to
// check that matched ParamDecl of the ancestor CallExpr is not rvalue.
- Finder->addMatcher(
- cxxConstructExpr(
- StringConstructorExpr, hasArgument(0, StringCStrCallExpr),
- unless(matchedParamDeclOfAncestorCallExprHasRValueRefType())),
- this);
+ Finder->addMatcher(cxxConstructExpr(StringConstructorExpr,
+ hasArgument(0, StringCStrCallExpr),
+ unless(hasParent(materializeTemporaryExpr(
+ unless(isBoundToLValue()))))),
+ this);
// Detect: 's == str.c_str()' -> 's == str'
Finder->addMatcher(
m1tp m1p2 = m1;
m1p2(s.c_str());
}
+
+namespace PR45286 {
+struct Foo {
+ void func(const std::string &) {}
+ void func2(std::string &&) {}
+};
+
+void bar() {
+ std::string Str{"aaa"};
+ Foo Foo;
+ Foo.func(Str.c_str());
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}Foo.func(Str);{{$}}
+
+ // Ensure it doesn't transform Binding to r values
+ Foo.func2(Str.c_str());
+
+ // Ensure its not confused by parens
+ Foo.func((Str.c_str()));
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call to 'c_str' [readability-redundant-string-cstr]
+ // CHECK-FIXES: {{^ }}Foo.func((Str));{{$}}
+ Foo.func2((Str.c_str()));
+}
+} // namespace PR45286