Rewriter object is not resetting correctly

Hello,

I’m having a strange problem with my clang tool and I would like to report it because maybe I’m doing something wrong, but it might be a bug.

My tool simply takes a source file, performs a change in the code and saves the new version. The program is under the version control system git and the new version is stored in a new git branch. This process is done a finite number of times and I reset the Rewriter object between a version and the next one (so that the change is not present in the rest of versions) in the following way:

Rewrite = Rewriter();
Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts());

Everything seemed to work right, but the other day I tested my tool with a program and I found something really strange. The problem is that the first and only the first change performed in the code remains in all the following versiones. For instance, if I insert a comment in each of the lines:

Original:
int method(int a){
int b = a + 1;
return b;
}

First version:
/1/ int method(int a){
int b = a + 1;
return b;
}

Second version:
/1/ int method(int a){
/2/ int b = a + 1;
return b;
}

Third version:
/1/ int method(int a){
int b = a + 1;
/3/ return b;
}

The problem is that the comment “/1/” should be only in the first version, but not in the rest. As you can see, “/2/” is not in the third version and that is the expected.

I have tried a lot of things, but nothing seems to solve this issue that only appears in this and other program that I tested today.

What could be happening here?

Thanks in advance.

Hello,

I'm having a strange problem with my clang tool and I would like to report
it because maybe I'm doing something wrong, but it might be a bug.

My tool simply takes a source file, performs a change in the code and
saves the new version. The program is under the version control system git
and the new version is stored in a new git branch. This process is done a
finite number of times and I reset the Rewriter object between a version
and the next one (so that the change is not present in the rest of
versions) in the following way:

Rewrite = Rewriter();
Rewrite.setSourceMgr(Context->getSourceManager(), Context->getLangOpts());

Everything seemed to work right, but the other day I tested my tool with a
program and I found something really strange. The problem is that the first
and only the first change performed in the code remains in all the
following versiones. For instance, if I insert a comment in each of the
lines:

Original:
int method(int a){
    int b = a + 1;
    return b;
}

First version:
/*1*/ int method(int a){
    int b = a + 1;
    return b;
}

Second version:
/*1*/ int method(int a){
/*2*/ int b = a + 1;
          return b;
}

Third version:
/*1*/ int method(int a){
          int b = a + 1;
/*3*/ return b;
}

The problem is that the comment "/*1*/" should be only in the first
version, but not in the rest. As you can see, "/*2*/" is not in the third
version and that is the expected.

I have tried a lot of things, but nothing seems to solve this issue that
only appears in this and other program that I tested today.

What could be happening here?

Thanks in advance.

My suggestion would be to output all the changes first, and then apply them
with a newly created source-manager and rewriter after-the-fact. That way,
you avoid any problems of how the source manager and rewriter interact.

Hi Manuel,

Thanks for answering, but I’m not quite sure about your suggestion. I want to remark that if I save each version in a file with a new name without using git, the versions are generated correctly (so the output of the changes is right). The problem that I comment arises when switching my tool to use git branches instead of generating new files.

So, I follow the next steps:

  • Take the ASTContext object → Context = Result.Context (where Result comes from “run(const MatchFinder::MatchResult &Result)” )
  • Reset the Rewriter object.
  • Do the change in the Rewriter object (replace, insert, etc).
  • Create and checkout to a new branch.
  • Take the content of the buffer relating the file from the Rewriter and save the content in the file of the actual branch.
  • Commit the revision.
  • Clean the branch and turn back to the main branch (the original version without any changes).

And repeat all the steps again and again. When a file is changed for the first time, that change remains during the whole process. Even if a file is modified for the first time when five changes have been performed in other file, that change will be present in the following versions of that file.

To get back to the point, I cannot see how using a new Rewriter and SourceManager object can help in this case because the problem appears when I make a change using the Rewriter object, commit a new branch and then reset the Rewriter. The first modification is always there! When you say “output”, do you mean to not change the Rewriter object and “save the state” (for instance the file, location and change to undertake) to be able to reproduce it later on? I don’t think it were so easy in my case… Could you be more specific?

Thanks again.

Hi Manuel,

Thanks for answering, but I'm not quite sure about your suggestion. I want
to remark that if I save each version in a file with a new name without
using git, the versions are generated correctly (so the output of the
changes is right). The problem that I comment arises when switching my tool
to use git branches instead of generating new files.

If that's the case, then I'm not sure how this question is related to clang
at all... (?)
It seems to me that the problem is less one of git branches, but that you
are changing the source files while the tool is running. If that is the
case, note that the SourceManager and FileManager do some caching of
content, so you might run into arbitrary fun if you try to do that.
If that is not the case I haven't understood the problem...

Cheers,
/Manuel