<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">I just made a branch on my tooling repo to attack your issue. See <a href="https://github.com/firolino/clang-tool/blob/nat-example/src/transformer/nattransformer.cc">https://github.com/firolino/clang-tool/blob/nat-example/src/transformer/nattransformer.cc</a><div><br></div><div>Just execute "bin/clang-tool ../examples/simple.cc --". It transforms </div><div><br></div><div><div>int getXXY(struct _x *p)</div><div>{</div><div>    p->x->y;</div><div>    return( p->x->x->y);</div><div>}</div></div><div><br></div><div>to</div><div><br></div><div><div>int getXXY(struct _x *p)</div><div>{</div><div>    getX(p)->y;</div><div>    return( getX(getX(p))->y);</div><div>}</div></div><div><br></div><div>Hopefully it helps you. I had the same issues as you have in the past as well. Mostly cause of ReplaceText. So I stopped using it :)</div><div><br></div></div></div></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">Am Di., 7. Mai 2019 um 13:18 Uhr schrieb Nat! via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">For ease of reproduction I put everything together into a small github <br>
project.<br>
<br>
<br>
<a href="https://github.com/mulle-nat-stash/cfe-mailinglist" rel="noreferrer" target="_blank">https://github.com/mulle-nat-stash/cfe-mailinglist</a><br>
<br>
<br>
Assuming I didn't goof completely, I can think of three ways this could <br>
be fixable:<br>
<br>
* abort visiting after the first substitution and reparse everything (I <br>
don't know how to do this, but I can probably find out)<br>
<br>
* hack the AST on the fly to represent the change from MemberExpr to a <br>
FunctionCall (I don't know if this would help at all)<br>
<br>
* get a second SourceManager on the RewriteBuffer and calculate extents <br>
with it (I don't know how and if this is possible either)<br>
<br>
<br>
Ciao<br>
<br>
    Nat!<br>
<br>
<br>
On 05.05.19 13:33, Nat! via cfe-dev wrote:<br>
> I think this is the simplest code, that exhibits my problem.<br>
><br>
> This code rewrites direct struct access like p->x<br>
><br>
> into a C function-call getX( p).<br>
><br>
><br>
> ```<br>
><br>
> //------------------------------------------------------------------------------ <br>
><br>
> // Tooling sample. Demonstrates:<br>
> //<br>
> // * How to write a simple source tool using libTooling.<br>
> // * How to use RecursiveASTVisitor to find interesting AST nodes.<br>
> // * How to use the Rewriter API to rewrite the source code.<br>
> //<br>
> // Eli Bendersky (<a href="mailto:eliben@gmail.com" target="_blank">eliben@gmail.com</a>)<br>
> // This code is in the public domain<br>
> //------------------------------------------------------------------------------ <br>
><br>
> #include <sstream><br>
> #include <string><br>
><br>
> #include "clang/AST/AST.h"<br>
> #include "clang/AST/ASTConsumer.h"<br>
> #include "clang/AST/RecursiveASTVisitor.h"<br>
> #include "clang/Frontend/ASTConsumers.h"<br>
> #include "clang/Frontend/CompilerInstance.h"<br>
> #include "clang/Frontend/FrontendActions.h"<br>
> #include "clang/Rewrite/Core/Rewriter.h"<br>
> #include "clang/Tooling/CommonOptionsParser.h"<br>
> #include "clang/Tooling/Tooling.h"<br>
> #include "llvm/Support/raw_ostream.h"<br>
><br>
> using namespace clang;<br>
> using namespace clang::driver;<br>
> using namespace clang::tooling;<br>
><br>
> static llvm::cl::OptionCategory ToolingSampleCategory("Tooling Sample");<br>
><br>
> // By implementing RecursiveASTVisitor, we can specify which AST nodes<br>
> // we're interested in by overriding relevant methods.<br>
> class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {<br>
> public:<br>
>   MyASTVisitor(Rewriter &R) : TheRewriter(R) {}<br>
><br>
>   bool VisitMemberExpr(MemberExpr *Expr) {<br>
>     SourceManager   *SM;<br>
>     int             length;<br>
>     const char      *startBuf;<br>
>     const char      *endBuf;<br>
>     const char      *opBuf;<br>
><br>
>     SM       = &TheRewriter.getSourceMgr();<br>
>     startBuf = SM->getCharacterData( Expr->getBeginLoc());<br>
>     opBuf    = SM->getCharacterData( Expr->getOperatorLoc());<br>
>     endBuf   = SM->getCharacterData( Expr->getEndLoc());<br>
>     length   = endBuf - startBuf;<br>
><br>
>     std::string  front( startBuf, opBuf - startBuf);<br>
><br>
>     length  += Lexer::MeasureTokenLength( Expr->getEndLoc(), *SM, <br>
> TheRewriter.getLangOpts());<br>
><br>
>     std::string  origin( startBuf, length);<br>
>     std::string  replace;<br>
><br>
>     replace = std::string( "getX(") + front + std::string( ")");<br>
><br>
>     fprintf( stderr, "rewrite: \"%s\" -> \"%s\"\n", origin.c_str(), <br>
> replace.c_str());<br>
>     TheRewriter.ReplaceText( Expr->getBeginLoc(), length, replace);<br>
><br>
>     return true;<br>
>   }<br>
><br>
> private:<br>
>   Rewriter &TheRewriter;<br>
> };<br>
><br>
><br>
> // Implementation of the ASTConsumer interface for reading an AST <br>
> produced<br>
> // by the Clang parser.<br>
> class MyASTConsumer : public ASTConsumer {<br>
> public:<br>
>   MyASTConsumer(Rewriter &R) : Visitor(R) {}<br>
><br>
>   // Override the method that gets called for each parsed top-level<br>
>   // declaration.<br>
>   bool HandleTopLevelDecl(DeclGroupRef DR) override {<br>
>     for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; <br>
> ++b) {<br>
>       // Traverse the declaration using our AST visitor.<br>
>       Visitor.TraverseDecl(*b);<br>
>       (*b)->dump();<br>
>     }<br>
>     return true;<br>
>   }<br>
><br>
> private:<br>
>   MyASTVisitor Visitor;<br>
> };I changed my theory is,<br>
><br>
> // For each source file provided to the tool, a new FrontendAction is <br>
> created.<br>
> class MyFrontendAction : public ASTFrontendAction {<br>
> public:<br>
>   MyFrontendAction() {}<br>
>   void EndSourceFileAction() override {<br>
>     SourceManager &SM = TheRewriter.getSourceMgr();<br>
>     llvm::errs() << "** EndSourceFileAction for: "<br>
>                  << <br>
> SM.getFileEntryForID(SM.getMainFileID())->getName() << "\n";<br>
><br>
>     // Now emit the rewritten buffer.<br>
> TheRewriter.getEditBuffer(SM.getMainFileID()).write(llvm::outs());<br>
>   }<br>
><br>
>   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,<br>
>                                                  StringRef file) <br>
> override {<br>
>     llvm::errs() << "** Creating AST consumer for: " << file << "\n";<br>
>     TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());<br>
>     return llvm::make_unique<MyASTConsumer>(TheRewriter);<br>
>   }<br>
><br>
> private:<br>
>   Rewriter TheRewriter;<br>
> };<br>
><br>
> int main(int argc, const char **argv) {<br>
>   CommonOptionsParser op(argc, argv, ToolingSampleCategory);<br>
>   ClangTool Tool(op.getCompilations(), op.getSourcePathList());<br>
><br>
>   return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());<br>
> }<br>
> ```<br>
><br>
> With input<br>
><br>
><br>
> ```<br>
><br>
> struct _x<br>
> {<br>
>    struct _x  *x;<br>
>    int        y;<br>
> };<br>
><br>
><br>
> int   getXXY( struct _x *p)<br>
> {<br>
>    return( p->x->x->y);<br>
> }<br>
><br>
> ```<br>
><br>
> it produces<br>
><br>
> ```<br>
><br>
> RecordDecl 0x27cdad8 </usr/local/llvm/srcL/llvm-clang-samples/z.c:1:1, <br>
> line:5:1> line:1:8 struct _x definition<br>
> |-FieldDecl 0x282a620 <line:3:4, col:16> col:16 x 'struct _x *'<br>
> `-FieldDecl 0x282a680 <line:4:4, col:15> col:15 y 'int'<br>
> rewrite: "p->x->x->y" -> "getX(p->x->x)"<br>
> rewrite: "p->x->x" -> "getX(p->x)"<br>
> rewrite: "p->x" -> "getX(p)"<br>
> FunctionDecl 0x282a7e0 <br>
> </usr/local/llvm/srcL/llvm-clang-samples/z.c:8:1, line:11:1> line:8:7 <br>
> getXXY 'int (struct _x *)'<br>
> |-ParmVarDecl 0x282a6f0 <col:15, col:26> col:26 used p 'struct _x *'<br>
> `-CompoundStmt 0x282aa00 <line:9:1, line:11:1><br>
>   `-ReturnStmt 0x282a9f0 <line:10:4, col:22><br>
>     `-ImplicitCastExpr 0x282a9d8 <col:10, col:22> 'int' <LValueToRValue><br>
>       `-ParenExpr 0x282a9b8 <col:10, col:22> 'int' lvalue<br>
>         `-MemberExpr 0x282a988 <col:12, col:21> 'int' lvalue ->y <br>
> 0x282a680<br>
>           `-ImplicitCastExpr 0x282a970 <col:12, col:18> 'struct _x *' <br>
> <LValueToRValue><br>
>             `-MemberExpr 0x282a940 <col:12, col:18> 'struct _x *' <br>
> lvalue ->x 0x282a620<br>
>               `-ImplicitCastExpr 0x282a928 <col:12, col:15> 'struct _x <br>
> *' <LValueToRValue><br>
>                 `-MemberExpr 0x282a8f8 <col:12, col:15> 'struct _x *' <br>
> lvalue ->x 0x282a620<br>
>                   `-ImplicitCastExpr 0x282a8e0 <col:12> 'struct _x *' <br>
> <LValueToRValue><br>
>                     `-DeclRefExpr 0x282a8c0 <col:12> 'struct _x *' <br>
> lvalue ParmVar 0x282a6f0 'p' 'struct _x *'<br>
> ** EndSourceFileAction for: /usr/local/llvm/srcL/llvm-clang-samples/z.c<br>
> struct _x<br>
> {<br>
>    struct _x  *x;<br>
>    int        y;<br>
> };<br>
><br>
><br>
> int   getXXY( struct _x *p)<br>
> {<br>
>    return( getX(p)(p->x)>x->x));<br>
> }<br>
><br>
> ```<br>
><br>
> From a few more tests along the way, my current pet theory is, that <br>
> the change from member access to a function call is tripping something <br>
> up. If I rewrite just the righthand side of the expression, it works OK.<br>
><br>
><br>
> Ciao<br>
><br>
>    Nat!<br>
><br>
><br>
> On 04.05.19 14:28, Stephen Kelly via cfe-dev wrote:<br>
>> On 03/05/2019 14:28, Nat! via cfe-dev wrote:<br>
>>> It turns out the fix suggestion - at least as I implemented it - <br>
>>> works for simple cases, but not in general.<br>
>>><br>
>>> ```<br>
>>> endBuf  = SM->getCharacterData( Stmt->getRHS()->getEndLoc());<br>
>>> endBuf += Lexer::MeasureTokenLength( Stmt->getEndLoc(), *SM, <br>
>>> TheRewriter.getLangOpts());<br>
>>> ```<br>
>>><br>
>>> I believe the problem is that the SourceManager I am using<br>
>>> to "measure" the length is looking at the unmodified sourcecode. But<br>
>>> the RewriteBuffer may already contain changes.<br>
>>><br>
>>> So in my example if I am looking at `x = yyy` at the source but<br>
>>> in the rewrite buffer its now `x=yyy_renamed` it will not take the<br>
>>> extra characters into account.<br>
>>><br>
>>> I should be measuring the contents of the RewriteBuffer instead,<br>
>>> with likely another SourceManager, but I lack the expertise to set<br>
>>> this up.<br>
>><br>
>> Can you post a more-complete sscce example of what you are trying to do?<br>
>><br>
>> Thanks,<br>
>><br>
>> Stephen<br>
>><br>
>> _______________________________________________<br>
>> cfe-dev mailing list<br>
>> <a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
>> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
> _______________________________________________<br>
> cfe-dev mailing list<br>
> <a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</blockquote></div>