<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>