<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>I copied your code, replacing ReplaceText with InsertText and
      RemoveText to make my function read now:</p>
    <p><br>
    </p>
    <p>```</p>
    <p>  bool VisitMemberExpr(MemberExpr *Expr) {<br>
          TheRewriter.InsertText(Expr->getSourceRange().getBegin(),
      "getX(");<br>
          TheRewriter.InsertText(Expr->getOperatorLoc(), ")");<br>
          TheRewriter.RemoveText(SourceRange(Expr->getOperatorLoc(),
      Expr->getSourceRange().getEnd().getLocWithOffset(-1)));<br>
          return true;<br>
        }<br>
      ```</p>
    <p><br>
    </p>
    <p>and it works.  Thanks a lot Firat!<br>
    </p>
    <p>Nat!</p>
    <table class="highlight tab-size js-file-line-container"
      data-tab-size="8">
      <tbody>
        <tr>
          <td id="LC33" class="blob-code blob-code-inner js-file-line"><br>
            <br>
          </td>
        </tr>
        <tr>
        </tr>
      </tbody>
    </table>
    <div class="moz-cite-prefix">On 07.05.19 14:38, Firat Kasmis wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAC8rT18S0-qxqPYjWauKFfkme+y=dLAutxkdxeymJPZpm0jLkg@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <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"
                moz-do-not-send="true">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" moz-do-not-send="true">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" moz-do-not-send="true">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" moz-do-not-send="true">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" moz-do-not-send="true">cfe-dev@lists.llvm.org</a><br>
          >> <a
            href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev"
            rel="noreferrer" target="_blank" moz-do-not-send="true">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"
            moz-do-not-send="true">cfe-dev@lists.llvm.org</a><br>
          > <a
            href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev"
            rel="noreferrer" target="_blank" moz-do-not-send="true">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"
            moz-do-not-send="true">cfe-dev@lists.llvm.org</a><br>
          <a
            href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev"
            rel="noreferrer" target="_blank" moz-do-not-send="true">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>