27 const auto CallToStrcat =
28 callExpr(callee(functionDecl(hasName(
"::absl::StrCat"))));
29 const auto CallToStrappend =
30 callExpr(callee(functionDecl(hasName(
"::absl::StrAppend"))));
33 const auto CallToEither = callExpr(
34 callee(functionDecl(hasAnyName(
"::absl::StrCat",
"::absl::StrAppend"))));
36 callExpr(CallToStrcat, unless(hasAncestor(CallToEither))).bind(
"StrCat"),
38 Finder->addMatcher(CallToStrappend.bind(
"StrAppend"),
this);
51 StrCatCheckResult *CheckResult) {
52 if (Call->getNumArgs() == 0)
55 CheckResult->Hints.push_back(
56 FixItHint::CreateRemoval(CharSourceRange::getCharRange(
57 Call->getBeginLoc(), Call->getArg(0)->getBeginLoc())));
59 CheckResult->Hints.push_back(
60 FixItHint::CreateRemoval(CharSourceRange::getCharRange(
61 Call->getRParenLoc(), Call->getEndLoc().getLocWithOffset(1))));
66 StrCatCheckResult *CheckResult) {
67 const auto IsAlphanum = hasDeclaration(cxxMethodDecl(hasName(
"AlphaNum")));
68 static const auto *
const Strcat =
new auto(hasName(
"::absl::StrCat"));
69 const auto IsStrcat = cxxBindTemporaryExpr(
70 has(callExpr(callee(functionDecl(*Strcat))).bind(
"StrCat")));
71 if (
const auto *SubStrcatCall = selectFirst<const CallExpr>(
73 match(stmt(traverse(TK_AsIs,
74 anyOf(cxxConstructExpr(IsAlphanum,
75 hasArgument(0, IsStrcat)),
77 *Arg->IgnoreParenImpCasts(), *Result.Context))) {
84static StrCatCheckResult
processCall(
const CallExpr *RootCall,
bool IsAppend,
85 const MatchFinder::MatchResult &Result) {
86 StrCatCheckResult CheckResult;
87 std::deque<const CallExpr *> CallsToProcess = {RootCall};
89 while (!CallsToProcess.empty()) {
90 ++CheckResult.NumCalls;
92 const CallExpr *CallExpr = CallsToProcess.front();
93 CallsToProcess.pop_front();
95 int StartArg = CallExpr == RootCall && IsAppend;
96 for (
const auto *Arg : CallExpr->arguments()) {
99 if (
const clang::CallExpr *Sub =
101 CallsToProcess.push_back(Sub);
109 bool IsAppend =
false;
111 const CallExpr *RootCall =
nullptr;
112 if ((RootCall = Result.Nodes.getNodeAs<CallExpr>(
"StrCat")))
114 else if ((RootCall = Result.Nodes.getNodeAs<CallExpr>(
"StrAppend")))
119 if (RootCall->getBeginLoc().isMacroID()) {
127 const StrCatCheckResult CheckResult =
processCall(RootCall, IsAppend, Result);
128 if (CheckResult.NumCalls == 1) {
133 diag(RootCall->getBeginLoc(),
134 "multiple calls to 'absl::StrCat' can be flattened into a single call")
135 << CheckResult.Hints;