'Matching multiple arguments to a particular function individually with Clang AST matcher

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?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source