How to easily know which special member functions the compiler has chosen? - c++

The naïve approach of overriding each special memb func, and plonking a printf or cout in the body of each (e.g. C++: Implicit Member Functions here on SO; Vandevoorde and Josuttis call this "tracers"), does not appeal:
invasive, in terms of codebase delta
O(n), where n = |classes|, in terms of effort
possible observer effect
Giving -E (or -save-temps) to g++ causes the latter to emit a .ii file for every source .cpp (or .cxx) file; in such a .ii, the source will be annotated with the exact steps taken by the cpp preprocessor. I want, ideally, something similar but with source being instead annotated as
Foo baz;
//// Line 55, choosing Foo::Foo(); implicit; empty body
Foo qux(Bar::mkFoo(42));
//// Line 56, choosing Foo::Foo(int)
//// Line 56, choosing Foo::Foo(const Foo&)
//// Line 56, choosing Foo::~Foo(); implicit
Foo qux2(std::move(Bar::mkFoo(4.2)));
//// Line 57, choosing Foo::Foo(double)
//// Line 57, choosing Foo::Foo(Foo&&)
//// Line 57, choosing Foo::~Foo(); implicit
The ideal approach will show choices as made for the particular optimization options given to the compiler.
Anyone know of a way to achieve this desideratum with g++? I'm ready to start writing a g++ plugin, but figured to ask before reinventing this particular wheel.
If there's a way to do this with clang, that'd be good to know as well.
Many thanks in advance.

I would guess you can build something like this on top of clang. clang provides several libraries providing access to the internal data structures used, including an AST. The AST should contain lots of information, though, and it may not be obvious what's of interest.
For example, using this input
struct foo {
foo();
explicit foo(int);
foo(foo&&);
foo(foo const&);
~foo();
};
struct bar {
static auto mkfoo(int x) -> foo;
};
template <typename T>
auto move(T&& t) -> T&&;
int main() {
foo f0;
foo f1{bar::mkfoo(17)};
foo f2{move(bar::mkfoo(17))};
}
using the built-in command to dump the AST, i.e., using the command-line
clang -cc1 -std=c++11 -ast-dump ast.cpp
yields the following output below. If you look closely you will see most of the operations you are after. You may need to ignore the detail you are not interested, though.
TranslationUnitDecl 0x7fea3b82ccc0 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7fea3b82d200 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x7fea3b82d260 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x7fea3b82d620 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
|-CXXRecordDecl 0x7fea3b82d670 <ast.cpp:1:1, line:7:1> line:1:8 referenced struct foo definition
| |-CXXRecordDecl 0x7fea3b82d780 <col:1, col:8> col:8 implicit referenced struct foo
| |-CXXConstructorDecl 0x7fea3b82d8b0 <line:2:5, col:9> col:5 used foo 'void (void)'
| |-CXXConstructorDecl 0x7fea3b873260 <line:3:5, col:21> col:14 foo 'void (int)'
| | `-ParmVarDecl 0x7fea3b82d980 <col:18> col:21 'int'
| |-CXXConstructorDecl 0x7fea3b873420 <line:4:5, col:14> col:5 used foo 'void (struct foo &&)'
| | `-ParmVarDecl 0x7fea3b873360 <col:9, col:12> col:14 'struct foo &&'
| |-CXXConstructorDecl 0x7fea3b8735e0 <line:5:5, col:19> col:5 foo 'void (const struct foo &)'
| | `-ParmVarDecl 0x7fea3b873520 <col:9, col:18> col:19 'const struct foo &'
| `-CXXDestructorDecl 0x7fea3b8736f0 <line:6:5, col:10> col:5 used ~foo 'void (void) noexcept'
|-CXXRecordDecl 0x7fea3b8737e0 <line:9:1, line:11:1> line:9:8 struct bar definition
| |-CXXRecordDecl 0x7fea3b8738f0 <col:1, col:8> col:8 implicit struct bar
| `-CXXMethodDecl 0x7fea3b873af0 <line:10:5, col:33> col:17 used mkfoo 'auto (int) -> struct foo' static
| `-ParmVarDecl 0x7fea3b873990 <col:23, col:27> col:27 x 'int'
|-FunctionTemplateDecl 0x7fea3b873e70 <line:13:1, line:14:22> col:6 move
| |-TemplateTypeParmDecl 0x7fea3b873ba0 <line:13:11, col:20> col:20 referenced typename T
| |-FunctionDecl 0x7fea3b873dd0 <line:14:1, col:22> col:6 move 'auto (T &&) -> T &&'
| | `-ParmVarDecl 0x7fea3b873cc0 <col:11, col:15> col:15 t 'T &&'
| `-FunctionDecl 0x7fea3b8757b0 <col:1, col:22> col:6 used move 'auto (struct foo &&) -> struct foo &&'
| |-TemplateArgument type 'struct foo'
| `-ParmVarDecl 0x7fea3b8756b0 <col:11, col:15> col:15 t 'struct foo &&'
`-FunctionDecl 0x7fea3b873f10 <line:16:1, line:20:1> line:16:5 main 'int (void)'
`-CompoundStmt 0x7fea3b875a48 <col:12, line:20:1>
|-DeclStmt 0x7fea3b8740e0 <line:17:5, col:11>
| `-VarDecl 0x7fea3b874020 <col:5, col:9> col:9 f0 'struct foo' callinit
| `-CXXConstructExpr 0x7fea3b874078 <col:9> 'struct foo' 'void (void)'
|-DeclStmt 0x7fea3b875398 <line:18:5, col:27>
| `-VarDecl 0x7fea3b874110 <col:5, col:26> col:9 f1 'struct foo' listinit
| `-ExprWithCleanups 0x7fea3b875380 <col:9, col:26> 'struct foo'
| `-CXXConstructExpr 0x7fea3b875348 <col:9, col:26> 'struct foo' 'void (struct foo &&)' elidable
| `-MaterializeTemporaryExpr 0x7fea3b875330 <col:12, col:25> 'struct foo' xvalue
| `-CXXBindTemporaryExpr 0x7fea3b8752c8 <col:12, col:25> 'struct foo' (CXXTemporary 0x7fea3b8752c0)
| `-CallExpr 0x7fea3b875290 <col:12, col:25> 'struct foo'
| |-ImplicitCastExpr 0x7fea3b875278 <col:12, col:17> 'auto (*)(int) -> struct foo' <FunctionToPointerDecay>
| | `-DeclRefExpr 0x7fea3b8741b8 <col:12, col:17> 'auto (int) -> struct foo' lvalue CXXMethod 0x7fea3b873af0 'mkfoo' 'auto (int) -> struct foo'
| `-IntegerLiteral 0x7fea3b875200 <col:23> 'int' 17
`-DeclStmt 0x7fea3b875a30 <line:19:5, col:33>
`-VarDecl 0x7fea3b8753c0 <col:5, col:32> col:9 f2 'struct foo' listinit
`-ExprWithCleanups 0x7fea3b875a18 <col:9, col:32> 'struct foo'
`-CXXConstructExpr 0x7fea3b8759e0 <col:9, col:32> 'struct foo' 'void (struct foo &&)'
`-CallExpr 0x7fea3b875950 <col:12, col:31> 'struct foo':'struct foo' xvalue
|-ImplicitCastExpr 0x7fea3b875938 <col:12> 'auto (*)(struct foo &&) -> struct foo &&' <FunctionToPointerDecay>
| `-DeclRefExpr 0x7fea3b8758b0 <col:12> 'auto (struct foo &&) -> struct foo &&' lvalue Function 0x7fea3b8757b0 'move' 'auto (struct foo &&) -> struct foo &&' (FunctionTemplate 0x7fea3b873e70 'move')
`-MaterializeTemporaryExpr 0x7fea3b875980 <col:17, col:30> 'struct foo':'struct foo' xvalue
`-CXXBindTemporaryExpr 0x7fea3b875558 <col:17, col:30> 'struct foo' (CXXTemporary 0x7fea3b875550)
`-CallExpr 0x7fea3b875518 <col:17, col:30> 'struct foo'
|-ImplicitCastExpr 0x7fea3b875500 <col:17, col:22> 'auto (*)(int) -> struct foo' <FunctionToPointerDecay>
| `-DeclRefExpr 0x7fea3b8754a8 <col:17, col:22> 'auto (int) -> struct foo' lvalue CXXMethod 0x7fea3b873af0 'mkfoo' 'auto (int) -> struct foo'
`-IntegerLiteral 0x7fea3b8754e0 <col:28> 'int' 17

Related

No template specialization in the clang AST if a header is missing

Observation: Clang AST don't contain any template specialisation if a header file is missing. It is true even when the template got nothing to do with the header file.
For example,
#include "unknown_header.h"
template<class T>
T add(T x, T y) {return x + y;}
void sum(void)
{
add<double>(5.0, 6.0);
}
generate the FunctionTemplateDecl instance, which doesn't contain specialisation for type double.
But if we get rid of "unknown_header.h", resulting in successful compilation, we can see the specialisation using type double. The specialisation can be seen below after removing the header.
|-FunctionTemplateDecl 0x55ec327d83e8 <tmp.cpp:1:1, line:2:31> col:3 add
| |-TemplateTypeParmDecl 0x55ec327d80f0 <line:1:10, col:16> col:16 referenced class depth 0 index 0 T
| |-FunctionDecl 0x55ec327d8348 <line:2:1, col:31> col:3 add 'T (T, T)'
| | |-ParmVarDecl 0x55ec327d81c0 <col:7, col:9> col:9 referenced x 'T'
| | |-ParmVarDecl 0x55ec327d8238 <col:12, col:14> col:14 referenced y 'T'
| | `-CompoundStmt 0x55ec327d8580 <col:17, col:31>
| | `-ReturnStmt 0x55ec327d8570 <col:18, col:29>
| | `-BinaryOperator 0x55ec327d8550 <col:25, col:29> '<dependent type>' '+'
| | |-DeclRefExpr 0x55ec327d8510 <col:25> 'T' lvalue ParmVar 0x55ec327d81c0 'x' 'T'
| | `-DeclRefExpr 0x55ec327d8530 <col:29> 'T' lvalue ParmVar 0x55ec327d8238 'y' 'T'
| `-FunctionDecl 0x55ec327d8ae8 <col:1, col:31> col:3 used add 'double (double, double)'
| |-TemplateArgument type 'double'
| | `-BuiltinType 0x55ec327923c0 'double'
| |-ParmVarDecl 0x55ec327d8960 <col:7, col:9> col:9 used x 'double':'double'
| |-ParmVarDecl 0x55ec327d89d8 <col:12, col:14> col:14 used y 'double':'double'
| `-CompoundStmt 0x55ec327d8da8 <col:17, col:31>
| `-ReturnStmt 0x55ec327d8d98 <col:18, col:29>
| `-BinaryOperator 0x55ec327d8d78 <col:25, col:29> 'double' '+'
| |-ImplicitCastExpr 0x55ec327d8d48 <col:25> 'double':'double' <LValueToRValue>
| | `-DeclRefExpr 0x55ec327d8d08 <col:25> 'double':'double' lvalue ParmVar 0x55ec327d8960 'x' 'double':'double'
| `-ImplicitCastExpr 0x55ec327d8d60 <col:29> 'double':'double' <LValueToRValue>
| `-DeclRefExpr 0x55ec327d8d28 <col:29> 'double':'double' lvalue ParmVar 0x55ec327d89d8 'y' 'double':'double'
Question: What stops clang from generating the template specialisation if the header is missing?

Find all calls of function in instantiation of template functions with VisitCallExpr

I want to find all calls of function myFunction:
void myFunction(int value) {
}
template <typename T>
void wrapper(T value) {
myFunction(value);
}
int
main(int argc, char const* argv[]) {
wrapper<int>(42);
return 0;
}
The code of the visitor:
bool VisitCallExpr(CallExpr *Expr) {
if (Expr) {
Expr->dump();
auto decl = dyn_cast_or_null<FunctionDecl>(Expr->getCalleeDecl());
if (decl) {
decl->dump();
}
}
return true;
}
The visitor finds two calls: The call of myFunction in the template function wrapper and the call of wrapper itself. The AST for myFunction seems not to be complete since it called from a template function. I want the AST for every concrete call of wrapper.
CallExpr 0x564a42a6c018 '<dependent type>'
|-UnresolvedLookupExpr 0x564a42a6bfb0 '<overloaded function type>' lvalue (ADL) = 'myFunction' 0x564a42a6bb68
`-DeclRefExpr 0x564a42a6bff8 'T' lvalue ParmVar 0x564a42a6bd40 'value' 'T'
CallExpr 0x564a42a6c7c0 'void'
|-ImplicitCastExpr 0x564a42a6c7a8 'void (*)(int)' <FunctionToPointerDecay>
| `-DeclRefExpr 0x564a42a6c6f8 'void (int)' lvalue Function 0x564a42a6c5f8 'wrapper' 'void (int)' (FunctionTemplate 0x564a42a6bed8 'wrapper')
`-IntegerLiteral 0x564a42a6c418 'int' 42
When I take a look at the function decl of the call to wrapper I can see that there is indeed the CallExpr which I was looking for:
FunctionDecl 0x564a42a6c5f8 <...> line:510:6 used wrapper 'void (int)'
|-TemplateArgument type 'int'
| `-BuiltinType 0x564a42a24270 'int'
|-ParmVarDecl 0x564a42a6c538 <col:14, col:16> col:16 used value 'int':'int'
`-CompoundStmt 0x564a42a6c918 <col:23, line:512:1>
`-CallExpr 0x564a42a6c8d8 <line:511:3, col:19> 'void'
|-ImplicitCastExpr 0x564a42a6c8c0 <col:3> 'void (*)(int)' <FunctionToPointerDecay>
| `-DeclRefExpr 0x564a42a6c8a0 <col:3> 'void (int)' lvalue Function 0x564a42a6bb68 'myFunction' 'void (int)'
`-ImplicitCastExpr 0x564a42a6c900 <col:14> 'int':'int' <LValueToRValue>
`-DeclRefExpr 0x564a42a6c880 <col:14> 'int':'int' lvalue ParmVar 0x564a42a6c538 'value' 'int':'int'
But that node is never visited. I really don't know what I am doing wrong. Hope you can help me.
Just calling explicit TraverseDecl will get me the expected result:
bool VisitCallExpr(CallExpr *Expr) {
FunctionDecl *decl = dyn_cast_or_null<FunctionDecl>(Expr->getCalleeDecl());
if (Expr) {
Expr->dump();
if (decl) {
static bool tarverseTemplateSpecialization = false;
if (!tarverseTemplateSpecialization && decl->isFunctionTemplateSpecialization()) {
tarverseTemplateSpecialization = true;
TraverseDecl(decl);
tarverseTemplateSpecialization = false;
}
}
}
// ...
}

How do you match a C++ template function call using Clang AST matchers?

I am working on a small project where I am trying to implement a refactoring tool using Clang's LibTooling. As part of this project, I need to find calls to a specific function from a specific library.
My attempts at using clang-query to come up with the AST matchers have failed.
However, I have discovered the following:
I can successfully find calls to non-template functions using my AST matchers.
A similar AST matcher query fails to find calls to a template function.
I have written the following test program to be able to post it here as a self-sufficient example, without depending on the library that I am working with:
template <typename T>
int func1(T param) {
return 4;
}
int main() {
int value = 4;
int result = func1(value);
return 0;
}
In order to observe the generated AST by Clang, I compiled the above program by using:
clang -Xclang -ast-dump -fsyntax-only test.cpp
The following is the generated AST:
TranslationUnitDecl 0xad9088 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0xad9960 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0xad9620 '__int128'
|-TypedefDecl 0xad99d0 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0xad9640 'unsigned __int128'
|-TypedefDecl 0xad9d48 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag'
| `-RecordType 0xad9ac0 '__NSConstantString_tag'
| `-CXXRecord 0xad9a28 '__NSConstantString_tag'
|-TypedefDecl 0xad9de0 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0xad9da0 'char *'
| `-BuiltinType 0xad9120 'char'
|-TypedefDecl 0xb16e98 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
| `-ConstantArrayType 0xb16e40 '__va_list_tag [1]' 1
| `-RecordType 0xad9ed0 '__va_list_tag'
| `-CXXRecord 0xad9e38 '__va_list_tag'
|-FunctionTemplateDecl 0xb17160 <test.cpp:1:1, line:4:1> line:2:5 func1
| |-TemplateTypeParmDecl 0xb16ef0 <line:1:11, col:20> col:20 referenced typename depth 0 index 0 T
| |-FunctionDecl 0xb170c0 <line:2:1, line:4:1> line:2:5 func1 'int (T)'
| | |-ParmVarDecl 0xb16fc8 <col:11, col:13> col:13 param 'T'
| | `-CompoundStmt 0xb17238 <col:20, line:4:1>
| | `-ReturnStmt 0xb17228 <line:3:5, col:12>
| | `-IntegerLiteral 0xb17208 <col:12> 'int' 4
| `-FunctionDecl 0xb17700 <line:2:1, line:4:1> line:2:5 used func1 'int (int)'
| |-TemplateArgument type 'int'
| |-ParmVarDecl 0xb17608 <col:11, col:13> col:13 param 'int':'int'
| `-CompoundStmt 0xb17960 <col:20, line:4:1>
| `-ReturnStmt 0xb17950 <line:3:5, col:12>
| `-IntegerLiteral 0xb17208 <col:12> 'int' 4
`-FunctionDecl 0xb172a0 <line:6:1, line:10:1> line:6:5 main 'int ()'
`-CompoundStmt 0xb17928 <col:12, line:10:1>
|-DeclStmt 0xb17408 <line:7:5, col:18>
| `-VarDecl 0xb17380 <col:5, col:17> col:9 used value 'int' cinit
| `-IntegerLiteral 0xb173e8 <col:17> 'int' 4
|-DeclStmt 0xb178e0 <line:8:5, col:30>
| `-VarDecl 0xb17438 <col:5, col:29> col:9 result 'int' cinit
| `-CallExpr 0xb178a0 <col:18, col:29> 'int'
| |-ImplicitCastExpr 0xb17888 <col:18> 'int (*)(int)' <FunctionToPointerDecay>
| | `-DeclRefExpr 0xb17800 <col:18> 'int (int)' lvalue Function 0xb17700 'func1' 'int (int)' (FunctionTemplate 0xb17160 'func1')
| `-ImplicitCastExpr 0xb178c8 <col:24> 'int' <LValueToRValue>
| `-DeclRefExpr 0xb174e8 <col:24> 'int' lvalue Var 0xb17380 'value' 'int'
`-ReturnStmt 0xb17918 <line:9:5, col:12>
`-IntegerLiteral 0xb178f8 <col:12> 'int' 0
Now, based on what I could find from Introduction to the Clang AST and AST Matcher Reference, I came up with the following two AST matchers and tested in clang-query:
clang-query> match callExpr(callee(functionTemplateDecl(hasName("func1"))))
0 matches.
clang-query> match callExpr(hasDeclaration(functionTemplateDecl(hasName("func1"))))
0 matches.
They both return 0 matches. The same queries work if I change func1 so that it is not a template function, and if I change functionTemplateDecl to functionDecl.
Any ideas what's going on?
if you use functionDecl in your matcher, it should work on your template code as well.
1 template <typename T>
2 int func1(T param) {
3 return 4;
4 }
5
6 int func1(int param1, int param2) {
7 return 5;
8 }
9
10 int main() {
11 int value = 4;
12 int result = func1(value);
13 int result2 = func1(value, value);
14 return 0;
15 }
clang-query> match callExpr(callee(functionDecl(hasName("func1"))))
Match #1:
/.../test.cpp:12:18: note: "root" binds here
int result = func1(value);
^~~~~~~~~~~~
Match #2:
/.../test.cpp:13:19: note: "root" binds here
int result2 = func1(value, value);
^~~~~~~~~~~~~~~~~~~
2 matches.
if you want to go for the template instantiations, add a Narrowing matcher:
clang-query> match callExpr(callee(functionDecl(hasName("func1"), isTemplateInstantiation())))
Match #1:
/.../test.cpp:12:18: note: "root" binds here
int result = func1(value);
^~~~~~~~~~~~
1 match.

How to extract types and names from CXXMemberCallExpr?

I would like to extract the types and names of the entire caller object and parameter types of member call expressions made from the A::WriteData method definition.
class ostream {
public:
void write(char* c, unsigned int i) {
}
};
struct StringWrapper {
char c[30];
void Write(ostream& os) {
os.write((char*)&c, sizeof(c));
}
};
struct DoubleWrapper {
double d;
void Write(ostream& os) {
os.write((char*)&d, sizeof(d));
}
};
struct Data {
DoubleWrapper dw;
int i;
StringWrapper sw;
};
class A {
public:
void WriteData(ostream& os);
private:
Data* d;
};
void A::WriteData(ostream& os) {
os.write((char*)&d->i, sizeof(d->i));
d->dw.Write(os);
d->sw.Write(os);
}
The relevant part of clang's AST for the WriteData method is here-
`-CXXMethodDecl 0x1221980 parent 0x1221628 prev 0x12217f8 <line:29:1, line:33:1> line:29:9 WriteData 'void (class ostream &) __attribute__((thiscall))'
|-ParmVarDecl 0x1221908 <col:19, col:28> col:28 used os 'class ostream &'
`-CompoundStmt 0x1221d90 <col:32, line:33:1>
|-CXXMemberCallExpr 0x1221bc8 <line:30:5, col:40> 'void'
| |-MemberExpr 0x1221a30 <col:5, col:8> '<bound member function type>' .write 0x418a10
| | `-DeclRefExpr 0x1221a18 <col:5> 'class ostream' lvalue ParmVar 0x1221908 'os' 'class ostream &'
| |-CStyleCastExpr 0x1221b10 <col:14, col:25> 'char *' <BitCast>
| | `-UnaryOperator 0x1221ae8 <col:21, col:25> 'int *' prefix '&'
| | `-MemberExpr 0x1221aa0 <col:22, col:25> 'int' lvalue ->i 0x12215b0
| | `-ImplicitCastExpr 0x1221a90 <col:22> 'struct Data *' <LValueToRValue>
| | `-MemberExpr 0x1221a68 <col:22> 'struct Data *' lvalue ->d 0x12218a8
| | `-CXXThisExpr 0x1221a58 <col:22> 'class A *' this
| `-UnaryExprOrTypeTraitExpr 0x1221bb0 <col:28, col:39> 'unsigned int' sizeof
| `-ParenExpr 0x1221b98 <col:34, col:39> 'int' lvalue
| `-MemberExpr 0x1221b70 <col:35, col:38> 'int' lvalue ->i 0x12215b0
| `-ImplicitCastExpr 0x1221b60 <col:35> 'struct Data *' <LValueToRValue>
| `-MemberExpr 0x1221b38 <col:35> 'struct Data *' lvalue ->d 0x12218a8
| `-CXXThisExpr 0x1221b28 <col:35> 'class A *' this
|-CXXMemberCallExpr 0x1221ca0 <line:31:5, col:19> 'void'
| |-MemberExpr 0x1221c60 <col:5, col:11> '<bound member function type>' .Write 0x1221248
| | `-MemberExpr 0x1221c38 <col:5, col:8> 'struct DoubleWrapper' lvalue ->dw 0x1221570
| | `-ImplicitCastExpr 0x1221c28 <col:5> 'struct Data *' <LValueToRValue>
| | `-MemberExpr 0x1221c00 <col:5> 'struct Data *' lvalue ->d 0x12218a8
| | `-CXXThisExpr 0x1221bf0 <col:5> 'class A *' this
| `-DeclRefExpr 0x1221c88 <col:17> 'class ostream' lvalue ParmVar 0x1221908 'os' 'class ostream &'
`-CXXMemberCallExpr 0x1221d70 <line:32:5, col:19> 'void'
|-MemberExpr 0x1221d30 <col:5, col:11> '<bound member function type>' .Write 0x418d20
| `-MemberExpr 0x1221d08 <col:5, col:8> 'struct StringWrapper' lvalue ->sw 0x12215e8
| `-ImplicitCastExpr 0x1221cf8 <col:5> 'struct Data *' <LValueToRValue>
| `-MemberExpr 0x1221cd0 <col:5> 'struct Data *' lvalue ->d 0x12218a8
| `-CXXThisExpr 0x1221cc0 <col:5> 'class A *' this
`-DeclRefExpr 0x1221d58 <col:17> 'class ostream' lvalue ParmVar 0x1221908 'os' 'class ostream &'
In this case, the information I want from my matcher would be:
caller=os: ostream ; params= &d->i: int*, sizeof(d->i): size_t
caller=d->dw: DoubleWrapper ; params= os: ostream
caller=d->sw: StringWrapper ; params= os: ostream
I've tried the following matcher:
cxxMemberCallExpr(
allOf(
hasAncestor(
cxxMethodDecl(isDefinition(),
hasName("WriteData"))),
anyOf(callee(cxxMethodDecl(hasName("WriteData"))),
callee(cxxMethodDecl(hasName("write"))))
)).bind("write-call-expr")
This gives me the correct statements that I want to extract.
I've extracted the following (invalid c++ follows):
Parameter types by getting the QualType of the parameters as a
string:
cxxMemberCallExpr->getDirectCallee()->parameters()
The argument names:
cxxMemberCallExpr->getArg(i)->printPretty(...) // **is there a better way to do this?**
Type of the object caller:
cxxMemberCallExpr->getImplicitObjectArgument()->getType().getAsString()
Object caller method:
dyn_cast<MemberExpr>(cxxMemberCallExpr->getCallee())
->getMemberNameInfo().getName().getAsString()
How do I get the object caller itself?
Is there a better way to get the argument names that are passed to the Write methods?
Looking at the AST, I'm not sure where to start.

How to get the AST of a single cpp file with clang?

I know that it will never be fully accurate without the headers because C++ isn't context free.
Using the classic example of 'A B(C);', it means that it can be recognized as a function declaration or an object definition. Either is fine for me. I just need the file totally parsed.
I am not interested in the semantic analysis of the code, just in the syntactic one and AFAIK the grammar of clang is one of the best.
The problem is that in some scenarios clang is avoiding some declarations when it doesn't know the types although I guess it can correctly parse it.
See the following case. Content of class.cpp:
A::A() { }
A::~A() { }
void A::B() { }
A::C() { }
Executing the clang command line application:
$ clang -Xclang -ast-dump -fsyntax-only class.cpp
it's just recognizing as AST nodes the constructor and the last method.
typedef char *__builtin_va_list;
int A() (CompoundStmt 0x9a6a570 <class.cpp:3:8, col:10>)
int C() (CompoundStmt 0x9a6a600 <class.cpp:9:8, col:10>)
Is there any way to get the complete AST tree?
Thanks!
I'm not sure if this is what you need:
test.cpp:
class A {
A();
~A();
void B();
void C();
};
A::A() {}
A::~A() {}
void A::B() {}
void A::C() {}
To dump the AST use: clang -Xclang -ast-dump -fsyntax-only test.cpp
TranslationUnitDecl 0x204f150 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x204f690 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
|-TypedefDecl 0x204f6f0 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
|-TypedefDecl 0x204fab0 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]'
|-CXXRecordDecl 0x204fb00 <test.cpp:1:1, line:6:1> line:1:7 class A definition
| |-CXXRecordDecl 0x204fc10 <col:1, col:7> col:7 implicit class A
| |-CXXConstructorDecl 0x204fd10 <line:2:5, col:7> col:5 A 'void (void)'
| |-CXXDestructorDecl 0x2088cc0 <line:3:5, col:8> col:5 ~A 'void (void)'
| |-CXXMethodDecl 0x2088d90 <line:4:5, col:12> col:10 B 'void (void)'
| |-CXXMethodDecl 0x2088e50 <line:5:5, col:12> col:10 C 'void (void)'
| `-CXXConstructorDecl 0x2088f80 <line:1:7> col:7 implicit A 'void (const class A &)' inline noexcept-unevaluated 0x2088f80
| `-ParmVarDecl 0x20890c0 <col:7> col:7 'const class A &'
|-CXXConstructorDecl 0x2089120 parent 0x204fb00 prev 0x204fd10 <line:8:1, col:9> col:4 A 'void (void)'
| `-CompoundStmt 0x2089218 <col:8, col:9>
|-CXXDestructorDecl 0x2089280 parent 0x204fb00 prev 0x2088cc0 <line:9:1, col:10> col:4 ~A 'void (void)'
| `-CompoundStmt 0x2089368 <col:9, col:10>
|-CXXMethodDecl 0x20893c0 parent 0x204fb00 prev 0x2088d90 <line:10:1, col:14> col:9 B 'void (void)'
| `-CompoundStmt 0x2089498 <col:13, col:14>
`-CXXMethodDecl 0x20894f0 parent 0x204fb00 prev 0x2088e50 <line:11:1, col:14> col:9 C 'void (void)'
`-CompoundStmt 0x20895c8 <col:13, col:14>