I'm trying to match unnecessary calls to c_str()
when calling functions that are happy to take the std::string
directly so that I can remove the unnecessary call so that I can write a clang-tidy check to automatically turn statements like:
fmt::print("{} {}", s1.c_str(), s2.c_str());
into
fmt::print("{} {}", s1, s2);
Whilst I've been able to come up with a matcher that matches the entire statement, it would be more convenient if I could bind all the c_str
calls individually. I've tried
auto StringType = hasUnqualifiedDesugaredType(recordType(hasDeclaration(cxxRecordDecl(
hasName("::std::basic_string")))));
auto PrintCall = hasName("::fmt::print");
StatementMatcher CStrMatcher = traverse(
TK_AsIs, callExpr(callee(functionDecl(PrintCall)),
hasAnyArgument(cxxMemberCallExpr(
callee(cxxMethodDecl(hasName("c_str"))),
on(hasType(StringType))).bind("c_str")))
);
but I only get a single match no matter how many arguments call c_str
. Is there a way to iterate over the separate argument matches that I've bound, or do I need to iterate over all the arguments (whether they matched or not) myself in the check
member?