Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle C++ functions with clang API to insert code

Tags:

c++

clang

I need to preprocess some C++ files to automatically insert code for testing and profiling, and I need to do it with the clang API.

For now, I want to be able to do the following: If there is a function:

int SomeFn(int a, int b, int c) {
    doStuff();
}

I want to preprocess it, that it looks like this:

int SomeFn(int a, int b, int c) {
    cout << "SomeFn is invoked with the following arguments: a=" << a << ", b=" << b << ", c=" << c << endl;
    doStuff();
}

I've tried to extend ASTConsumer and use the methods HandleTopLevelDecl and HandleTopLevelSingleDecl and check if the passed Decls are FunctionDecls and downcast them, so I can get their names and body-locations. But I can't handle class-methods that way, only global functions.

I found a function in the ASTConsumer class HandleTagDeclDefinition(TagDecl* D). The documentation says:

This callback is invoked each time a TagDecl (e.g. struct, union, enum, class) is completed.

But it looks like this method isn't even invoked, when I test it.

So my question is, what would be the right way to do this task? And how are C++ classes are represented in the clang API? Maybe someone knows, where I can find examples because the clang API is poorly documented.


UPDATE:

I know there is also the concept of Visitors and there is a method VisitRecordDecl(RecordDecl *D). The documentation says that RecordDecl represents classes. So I extended RecursiveASTVisitor and implemented VisitRecordDecl(RecordDecl *D) but it seems, that this method isn't invoked neither. Instead VisitVarDecl is invoked, when a class definition is find, as if it is seen as a variable declaration. So I'm a bit confused. I hope, someone can help...


UPDATE2:

I tried to parse another file and this time clang found one RecordDecl. But the file defined one struct and two classes, so I think my clang code parses C instead of C++. Are there any settings to switch between C and C++ ?

like image 274
Baris Akar Avatar asked Jul 06 '11 21:07

Baris Akar


2 Answers

Are there any settings to switch between C and C++ ?

Finally I found out how to handle this:

I extended from ASTConsumer and RecursiveASTVisitor<MyConsumer> to traverse the AST and implemented VisitCXXRecordDecl(CXXRecordDecl* D). Then I had to set the LangOptions parameter for the preprocessor, so it parses C++.

langOpts.CPlusPlus = 1;

My fault was to think that it would parse C++ right away, but that was not the case, it parses C as default and so doesn't recognize classes.

like image 98
Baris Akar Avatar answered Oct 17 '22 16:10

Baris Akar


I'm wondering why you want to do this transform on the fly (if I understand you right). This is especially tricky with C++ methods defined in-class, since they're compiled as-if they're defined outside the class (i.e. all class members are usable, even those not declared yet).

Anyway, when you have a RecordDecl, you can access its members via field_begin.

Obviously, when you encounter nexted classes, you'll need to enumerate those as well. In fact, since you can define methods in classes in functions, you'll need to check for nested declarations almost everywhere.

like image 3
MSalters Avatar answered Oct 17 '22 17:10

MSalters