28 const auto IsCharPointerOrArray =
29 anyOf(hasType(pointerType(pointee(isAnyCharacter()))),
30 hasType(arrayType(hasElementType(isAnyCharacter()))));
32 const auto ImplicitlyConvertibleToStringView =
33 expr(anyOf(hasType(IsStdStringView), IsCharPointerOrArray,
34 hasType(IsStdString)))
35 .bind(
"originalStringView");
40 const auto RedundantStringConstruction = cxxConstructExpr(
42 hasArgument(0, ignoringImplicit(ImplicitlyConvertibleToStringView)),
43 unless(hasArgument(1, unless(cxxDefaultArgExpr()))));
47 const auto RedundantFunctionalCast = cxxFunctionalCastExpr(
48 hasType(IsStdString), hasDescendant(RedundantStringConstruction));
50 const auto RedundantTemporaryString =
51 expr(anyOf(RedundantStringConstruction, RedundantFunctionalCast));
54 const auto RedundantStringWithCStr =
55 cxxMemberCallExpr(callee(cxxMethodDecl(hasAnyName(
"c_str",
"data"))),
56 on(ignoringParenImpCasts(RedundantTemporaryString)));
62 callee(memberExpr(member(cxxConversionDecl(returns(IsStdStringView))),
63 has(ignoringImplicit(RedundantTemporaryString.bind(
71 hasArgument(0, RedundantStringWithCStr.bind(
"redundantExpr")))
77 const auto *StringView = Result.Nodes.getNodeAs<Expr>(
"stringView");
78 const auto *RedundantExpr = Result.Nodes.getNodeAs<Expr>(
"redundantExpr");
79 const auto *OriginalExpr = Result.Nodes.getNodeAs<Expr>(
"originalStringView");
80 assert(StringView && RedundantExpr && OriginalExpr);
82 bool IsCStrPattern =
false;
84 const auto *CStrCall = dyn_cast<CXXMemberCallExpr>(RedundantExpr);
85 if (CStrCall && CStrCall->getMethodDecl()) {
86 MethodName = CStrCall->getMethodDecl()->getName();
87 if (MethodName ==
"c_str" || MethodName ==
"data")
91 const StringRef OriginalText = Lexer::getSourceText(
92 CharSourceRange::getTokenRange(OriginalExpr->getSourceRange()),
93 *Result.SourceManager, getLangOpts());
95 if (OriginalText.empty())
98 const FixItHint FixRedundantConversion = FixItHint::CreateReplacement(
99 RedundantExpr->getSourceRange(), OriginalText);
100 if (IsCStrPattern && CStrCall) {
102 diag(RedundantExpr->getBeginLoc(),
103 "redundant conversion to %0 and calling .%1() and then back to %2")
104 << CStrCall->getImplicitObjectArgument()->getType() << MethodName
105 << StringView->getType() << FixRedundantConversion;
108 diag(RedundantExpr->getBeginLoc(),
109 "redundant conversion to %0 and then back to %1")
110 << RedundantExpr->getType() << StringView->getType()
111 << FixRedundantConversion;