<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none"><!--P{margin-top:0;margin-bottom:0;} .ms-cui-menu {background-color:#ffffff;border:1px rgb(171, 171, 171) solid;font-family:'Segoe UI WPC', 'Segoe UI', Tahoma, 'Microsoft Sans Serif', Verdana, sans-serif;font-size:11pt;color:rgb(51, 51, 51);} .ms-cui-menusection-title {display:none;} .ms-cui-ctl {vertical-align:text-top;text-decoration:none;color:rgb(51, 51, 51);} .ms-cui-ctl-on {background-color:rgb(223, 237, 250);opacity: 0.8;} .ms-cui-img-cont-float {display:inline-block;margin-top:2px} .ms-cui-smenu-inner {padding-top:0px;} .ms-owa-paste-option-icon {margin: 2px 4px 0px 4px;vertical-align:sub;padding-bottom: 2px;display:inline-block;} .ms-rtePasteFlyout-option:hover {background-color:rgb(223, 237, 250) !important;opacity:1 !important;} .ms-rtePasteFlyout-option {padding:8px 4px 8px 4px;outline:none;} .ms-cui-menusection {float:left; width:85px;height:24px;overflow:hidden}.wf {speak:none; font-weight:normal; font-variant:normal; text-transform:none; -webkit-font-smoothing:antialiased; vertical-align:middle; display:inline-block;}.wf-family-owa {font-family:'o365Icons'}@font-face {  font-family:'o365IconsIE8';  src:url('prem/15.0.888.16/resources/styles/office365icons.ie8.eot?#iefix') format('embedded-opentype'),         url('prem/15.0.888.16/resources/styles/office365icons.ie8.woff') format('woff'),         url('prem/15.0.888.16/resources/styles/office365icons.ie8.ttf') format('truetype');  font-weight:normal;  font-style:normal;}@font-face {  font-family:'o365IconsMouse';  src:url('prem/15.0.888.16/resources/styles/office365icons.mouse.eot?#iefix') format('embedded-opentype'),         url('prem/15.0.888.16/resources/styles/office365icons.mouse.woff') format('woff'),         url('prem/15.0.888.16/resources/styles/office365icons.mouse.ttf') format('truetype');  font-weight:normal;  font-style:normal;}.wf-family-owa {font-family:'o365IconsMouse'}.ie8 .wf-family-owa {font-family:'o365IconsIE8'}.ie8 .wf-owa-play-large:before {content:'\e254';}.notIE8 .wf-owa-play-large:before {content:'\e054';}.ie8 .wf-owa-play-large {color:#FFFFFF/*$WFWhiteColor*/;}.notIE8 .wf-owa-play-large {border-color:#FFFFFF/*$WFWhiteColor*/; width:1.4em; height:1.4em; border-width:.1em; border-style:solid; border-radius:.8em; text-align:center; box-sizing:border-box; -moz-box-sizing:border-box; padding:0.1em; color:#FFFFFF/*$WFWhiteColor*/;}.ie8 .wf-size-play-large {width:40px; height:40px; font-size:30px}.notIE8 .wf-size-play-large {width:40px; height:40px; font-size:30px}
<!--
.EmailQuote
        {margin-left:1pt;
        padding-left:4pt;
        border-left:#800000 2px solid}
-->
--></style>
</head>
<body>
<div style="font-size:12pt;color:#000000;background-color:#FFFFFF;font-family:Calibri,Arial,Helvetica,sans-serif;">
<p>I have found the AST Matcher Reference to be useful while developing matchers: <a href="http://clang.llvm.org/docs/LibASTMatchersReference.html">http://clang.llvm.org/docs/LibASTMatchersReference.html</a><br>
</p>
<p><br>
</p>
<p>Instead of writing your own debug matcher you may want to try clang-query.<br>
</p>
<p>I don't think it's documented yet but it's quite straightforward to get started. You will have an interactive shell session to build your matcher and see the results in live, I tried it the other day and I suggest to use it with libedit support so it will
 complete for you the possible matchers as you type.<br>
</p>
<p><br>
</p>
<p><a href="https://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/" title="https://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/
Ctrl+click or tap to follow link">https://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-query/</a>​<br>
</p>
<p><br>
</p>
<p>To generate the AST dump you may want to use clang-check instead of clang++ with all the arguments. clang-check allows you to filter the AST and remove the need of specifying things like -fsyntax-only.<br>
</p>
<p><br>
</p>
<p>I have found the ast-dump useful since it provides the names of the types that you can look for in the AST Matcher Reference.<br>
</p>
<p><br>
</p>
<div style="color: #282828;">
<div>
<hr tabindex="-1" style="display: inline-block; width: 98%;">
<div id="x_divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size: 11pt;"><b>From:</b> Stephen Kelly <steveire@gmail.com><br>
<b>Sent:</b> 11 March 2014 10:48<br>
<b>To:</b> cfe-dev@cs.uiuc.edu<br>
<b>Subject:</b> [cfe-dev] How to write a matcher?</font>
<div> </div>
</div>
</div>
<font size="2"><span style="font-size: 10pt;">
<div class="PlainText"><br>
Hi,<br>
<br>
I want to write a tool to remove c_str() calls in lines like<br>
<br>
 std::cout << s.c_str();<br>
<br>
There isn't really enough information about what matchers mean, and how to <br>
use them. <br>
<br>
There is no good information on how to write/debug them, and how they need <br>
to be arranged (nested, in an allof, wrapped with to(), on(), callee() etc).<br>
<br>
How does one *actually* go about doing it?<br>
<br>
Here's my attempt:<br>
<br>
My test code is:<br>
<br>
 int main(int, char **)<br>
 {<br>
   std::string s("something");<br>
   std::cout << s << std::endl;<br>
   std::cout << s.c_str() << std::endl;<br>
   return 0;<br>
 }<br>
<br>
I used<br>
<br>
 clang++ -Xclang -ast-dump -fsyntax-only -fno-color-diagnostics ../main.cpp <br>
<br>
to generate   <br>
<br>
 `-FunctionDecl 0x275cae0 <../main.cpp:9:1, line:16:1> main 'int (int, char <br>
**)'<br>
   |-ParmVarDecl 0x275c9a0 <line:9:10> 'int'<br>
   |-ParmVarDecl 0x275ca10 <col:15, col:21> 'char **'<br>
   `-CompoundStmt 0x275f150 <line:10:1, line:16:1><br>
     |-DeclStmt 0x275d160 <line:11:3, col:23><br>
     | `-VarDecl 0x275cc30 <col:3, col:22> s 'std::string':'class <br>
std::basic_string<char>'<br>
     |   `-ExprWithCleanups 0x275d148 <col:15, col:22> 'std::string':'class <br>
std::basic_string<char>'<br>
     |     `-CXXConstructExpr 0x275d108 <col:15, col:22> <br>
'std::string':'class std::basic_string<char>' 'void (const char *, const <br>
class std::allocator<char> &)'<br>
     |       |-ImplicitCastExpr 0x275cd20 <col:17> 'const char *' <br>
<ArrayToPointerDecay><br>
     |       | `-StringLiteral 0x275cc88 <col:17> 'const char [4]' lvalue <br>
"wtf"<br>
     |       `-CXXDefaultArgExpr 0x275d0e0 <<invalid sloc>> 'const class <br>
std::allocator<char>':'const class std::allocator<char>' lvalue<br>
     |-CXXOperatorCallExpr 0x275e160 <line:12:3, col:26> <br>
'__ostream_type':'class std::basic_ostream<char>' lvalue<br>
     | |-ImplicitCastExpr 0x275e148 <col:18> '__ostream_type &(*)<br>
(__ostream_type &(*)(__ostream_type &))' <FunctionToPointerDecay><br>
     | | `-DeclRefExpr 0x275e0c0 <col:18> '__ostream_type &(__ostream_type <br>
&(*)(__ostream_type &))' lvalue CXXMethod 0x26d0410 'operator<<' <br>
'__ostream_type &(__ostream_type &(*)(__ostream_type &))'<br>
     | |-CXXOperatorCallExpr 0x275d5c0 <col:3, col:16> 'basic_ostream<char, <br>
struct std::char_traits<char> >':'class std::basic_ostream<char>' lvalue<br>
     | | |-ImplicitCastExpr 0x275d5a8 <col:13> 'basic_ostream<char, struct <br>
std::char_traits<char> > &(*)(basic_ostream<char, struct <br>
std::char_traits<char> > &, const basic_string<char, struct <br>
std::char_traits<char>, class std::allocator<char> > &)' <br>
<FunctionToPointerDecay><br>
     | | | `-DeclRefExpr 0x275d528 <col:13> 'basic_ostream<char, struct <br>
std::char_traits<char> > &(basic_ostream<char, struct std::char_traits<char> <br>
> &, const basic_string<char, struct std::char_traits<char>, class <br>
std::allocator<char> > &)' lvalue Function 0x2533250 'operator<<' <br>
'basic_ostream<char, struct std::char_traits<char> > &(basic_ostream<char, <br>
struct std::char_traits<char> > &, const basic_string<char, struct <br>
std::char_traits<char>, class std::allocator<char> > &)'<br>
     | | |-DeclRefExpr 0x275d198 <col:3, col:8> 'ostream':'class <br>
std::basic_ostream<char>' lvalue Var 0x275c3a0 'cout' 'ostream':'class <br>
std::basic_ostream<char>'<br>
     | | `-ImplicitCastExpr 0x275d510 <col:16> 'const basic_string<char, <br>
struct std::char_traits<char>, class std::allocator<char> >':'const class <br>
std::basic_string<char>' lvalue <NoOp><br>
     | |   `-DeclRefExpr 0x275d1d0 <col:16> 'std::string':'class <br>
std::basic_string<char>' lvalue Var 0x275cc30 's' 'std::string':'class <br>
std::basic_string<char>'<br>
     | `-ImplicitCastExpr 0x275e0a8 <col:21, col:26> 'basic_ostream<char, <br>
struct std::char_traits<char> > &(*)(basic_ostream<char, struct <br>
std::char_traits<char> > &)' <FunctionToPointerDecay><br>
     |   `-DeclRefExpr 0x275e068 <col:21, col:26> 'basic_ostream<char, <br>
struct std::char_traits<char> > &(basic_ostream<char, struct <br>
std::char_traits<char> > &)' lvalue Function 0x26d4480 'endl' <br>
'basic_ostream<char, struct std::char_traits<char> > &(basic_ostream<char, <br>
struct std::char_traits<char> > &)' (FunctionTemplate 0x26b9180 'endl')<br>
     |-CXXOperatorCallExpr 0x275f0c8 <line:13:3, col:34> <br>
'__ostream_type':'class std::basic_ostream<char>' lvalue<br>
     | |-ImplicitCastExpr 0x275f0b0 <col:26> '__ostream_type &(*)<br>
(__ostream_type &(*)(__ostream_type &))' <FunctionToPointerDecay><br>
     | | `-DeclRefExpr 0x275f088 <col:26> '__ostream_type &(__ostream_type <br>
&(*)(__ostream_type &))' lvalue CXXMethod 0x26d0410 'operator<<' <br>
'__ostream_type &(__ostream_type &(*)(__ostream_type &))'<br>
     | |-CXXOperatorCallExpr 0x275e610 <col:3, col:24> 'basic_ostream<char, <br>
struct std::char_traits<char> >':'class std::basic_ostream<char>' lvalue<br>
     | | |-ImplicitCastExpr 0x275e5f8 <col:13> 'basic_ostream<char, struct <br>
std::char_traits<char> > &(*)(basic_ostream<char, struct <br>
std::char_traits<char> > &, const char *)' <FunctionToPointerDecay><br>
     | | | `-DeclRefExpr 0x275e578 <col:13> 'basic_ostream<char, struct <br>
std::char_traits<char> > &(basic_ostream<char, struct std::char_traits<char> <br>
> &, const char *)' lvalue Function 0x26d9830 'operator<<' <br>
'basic_ostream<char, struct std::char_traits<char> > &(basic_ostream<char, <br>
struct std::char_traits<char> > &, const char *)'<br>
     | | |-DeclRefExpr 0x275e1c8 <col:3, col:8> 'ostream':'class <br>
std::basic_ostream<char>' lvalue Var 0x275c3a0 'cout' 'ostream':'class <br>
std::basic_ostream<char>'<br>
     | | `-CXXMemberCallExpr 0x275e258 <col:16, col:24> 'const char *'<br>
     | |   `-MemberExpr 0x275e228 <col:16, col:18> '<bound member function <br>
type>' .c_str 0x252c400<br>
     | |     `-ImplicitCastExpr 0x275e280 <col:16> 'const class <br>
std::basic_string<char>' lvalue <NoOp><br>
     | |       `-DeclRefExpr 0x275e200 <col:16> 'std::string':'class <br>
std::basic_string<char>' lvalue Var 0x275cc30 's' 'std::string':'class <br>
std::basic_string<char>'<br>
     | `-ImplicitCastExpr 0x275f070 <col:29, col:34> 'basic_ostream<char, <br>
struct std::char_traits<char> > &(*)(basic_ostream<char, struct <br>
std::char_traits<char> > &)' <FunctionToPointerDecay><br>
     |   `-DeclRefExpr 0x275f030 <col:29, col:34> 'basic_ostream<char, <br>
struct std::char_traits<char> > &(basic_ostream<char, struct <br>
std::char_traits<char> > &)' lvalue Function 0x26d4480 'endl' <br>
'basic_ostream<char, struct std::char_traits<char> > &(basic_ostream<char, <br>
struct std::char_traits<char> > &)' (FunctionTemplate 0x26b9180 'endl')<br>
     `-ReturnStmt 0x275f130 <line:14:3, col:10><br>
       `-IntegerLiteral 0x275f110 <col:10> 'int' 0<br>
 <br>
<br>
It seems useful to writing a matcher.<br>
<br>
I modified the removeCStrCalls tool with a debugging matcher, so that I can <br>
start broad, and incrementally narrow what I want to match, while printing <br>
out what I have actually matched:<br>
<br>
 class Debugging : public ast_matchers::MatchFinder::MatchCallback {<br>
 public:<br>
   Debugging(tooling::Replacements *Replace)<br>
     : Replace(Replace) {}<br>
<br>
   virtual void run(const ast_matchers::MatchFinder::MatchResult &Result) {<br>
<br>
     const Expr *Arg =<br>
         Result.Nodes.getStmtAs<Expr>("match");<br>
     std::string match = getText(*Result.SourceManager, *Arg);<br>
     std::cout << "MATCH " << match << std::endl;<br>
<br>
   }<br>
<br>
 private:<br>
   tooling::Replacements *Replace;<br>
 };<br>
<br>
Is this the right/sane/only possible approach to the act of writing a <br>
matcher?<br>
<br>
>From the -ast-dump, it looks like I need to first match a <br>
CXXOperatorCallExpr, so I write this matcher:<br>
<br>
  Finder.addMatcher(<br>
      id("match", operatorCallExpr()),<br>
      &Callback);<br>
<br>
which gives me lots of output, mostly from the iostream header. I need to <br>
get narrower.<br>
<br>
In the -ast-dump output there is a CXXMemberCallExpr nested in the <br>
CXXOperatorCallExpr. I make a logical jump at matching that:<br>
<br>
  Finder.addMatcher(<br>
      id("match", operatorCallExpr(memberCallExpr())),<br>
      &Callback);<br>
<br>
However, that produces no output, so my logical jump must be incorrect.<br>
<br>
What is the correct logical jump here in order to narrow my match? <br>
<br>
How can I determine what logical jumps I can make, by looking at the ast-<br>
dump output? <br>
<br>
How does one go about *actually* writing matcher code? <br>
<br>
What is the understanding one must have, the logic one must have and the <br>
information one must have to hand (is ast-dump output useful or not)?<br>
<br>
To be clear (in case it is not already clear), I'm not looking for a <br>
finished solution for the match/replacement I'm trying to make. I'm asking <br>
what to spend time doing between opening my editor and running a tool that <br>
does what I need. How do I figure out what code I need to write?<br>
<br>
Note: I have read the docs. The section at<br>
<br>
 <a href="http://clang.llvm.org/docs/LibASTMatchersTutorial.html#step-2-using-ast-matchers">http://clang.llvm.org/docs/LibASTMatchersTutorial.html#step-2-using-ast-matchers</a><br>
<br>
shows some incremental steps, but does not explain how they are chosen. <br>
<br>
How does one know to go from <br>
<br>
 forStmt()<br>
<br>
to <br>
<br>
 forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl()))))<br>
<br>
for example? That is the kind of information I am looking for.<br>
<br>
Thanks,<br>
<br>
Steve.<br>
<br>
<br>
<br>
</div>
</span></font></div>
</div>
</body>
</html>