Finding all references to a function overload or type.

Dear all,

I would like to use the clang infrastructure (libclang, libtooling, ...) to find all references to a function overload or a type in a program. This should also work if the program has templates.

Consider the following example:

void f(int i)
{}

template <typename T>
void f(T x)
{
  X<T> y;
}

template <typename T>
struct X
{};

template <>
struct X<long>
{};

main ()
{
  f(3.0);
  f(1);
  f(1l);

  return 0;
}

For example, I would like to find all occurences of the overload "void f(int i)" (result should be the line with "f(1)" or all occurences of the specialization "X<long>" (in the line with "X<T> y" when f is called with a long value.

Is this possible with clang? If so, can anyone point me in the right direction?

Thanks,
Manuel

Dear all,

I would like to use the clang infrastructure (libclang, libtooling, ...)
to find all references to a function overload or a type in a program. This
should also work if the program has templates.

Consider the following example:

void f(int i)
{}

template <typename T>
void f(T x)
{
  X<T> y;
}

template <typename T>
struct X
{};

template <>
struct X<long>
{};

main ()
{
  f(3.0);
  f(1);
  f(1l);

  return 0;
}

For example, I would like to find all occurences of the overload "void
f(int i)" (result should be the line with "f(1)" or all occurences of the
specialization "X<long>" (in the line with "X<T> y" when f is called with a
long value.

Is this possible with clang? If so, can anyone point me in the right
direction?

Yes. Start here: http://clang.llvm.org/docs/Tooling.html

Cheers,
/Manuel

Thank you for your answer.

I was able to write a small test program with an RecursiveASTVisitor [1] by using some example code I found on github.

However, now I’m stuck. I could not find out how to find out that the function overload bar(Foo<int, Tick> const &) is called from the AST.

Can someone help me with this and point me into the right direction again?

Thanks,
Manuel

[1] https://github.com/holtgrewe/func_references/blob/master/src/test.cpp

ping

Maybe I should elaborate a bit further.

Given the program [1] (written as a string in the test), I would like to find out from which contextes the function overload bar(Foo<T, Tick> const &) is called.

I tried dumping parts of the AST and from that it appears that it is not directly possible to see the instantiation points. Is it possible to see a “concrete AST” with instantiated class and function templates?

Thanks,
Manuel

[1] https://github.com/holtgrewe/func_references/blob/master/src/test.cpp#L114

ping

Maybe I should elaborate a bit further.

Given the program [1] (written as a string in the test), I would like to
find out from which contextes the function overload bar(Foo<T, Tick> const
&) is called.

I tried dumping parts of the AST and from that it appears that it is not
directly possible to see the instantiation points. Is it possible to see a
"concrete AST" with instantiated class and function templates?

What's your "key" for the overload of bar in this case?
Possible keys:
a) the location of the function declaration / definition
b) the parameter list

Cheers,
/Manuel

Hi,

the location of the function declaration/definition appears to be easier to construct and would work fine for me.

Thanks,
Manuel

Hi,

the location of the function declaration/definition appears to be easier
to construct and would work fine for me.

Then you'll basically want to drill through the AST from the call to the
declaration, and get the location of the declaration via the SourceManager.

Cheers,
/Manuel

Hi Manuel,

Thank you for your answer. I think I figured it out. Here is a quick explanation of my problem to help out others who stumble over this problem.

My problem was how to get from the template function to the instantiation thereof. A look at the output of -dump-ast, however, showed me that the AST contains the whole instantiation.

Below is the AST dump of the small example program and the program itself.

Thanks,
Manuel

typedef __int128 __int128_t;
typedef unsigned __int128 __uint128_t;
template struct Foo {
struct Foo;
inline Foo() throw() (CompoundStmt 0x27f6270 <ast_demo.cpp:8:8>)

inline Foo(const Foo<int, Tick> &) throw();
}
template <typename T, typename TSpec> struct Foo;
struct Tick {
struct Tick;
inline Tick() throw();
inline Tick(const Tick &) throw();
inline void ~Tick() throw() (CompoundStmt 0x27f56e8 <ast_demo.cpp:4:8>)

};
struct Tock {
struct Tock;
};
struct Foo {
struct Foo;
};
template int bar(const Foo<int, Tick> &x) (CompoundStmt 0x27f72c0 <ast_demo.cpp:13:1, col:13>
(ReturnStmt 0x27f72a0 <col:3, col:10>
(IntegerLiteral 0x27f1a70 col:10 ‘int’ 1)))

template int bar(const Foo<T, Tick> &x) (CompoundStmt 0x27f1ab0 <ast_demo.cpp:13:1, col:13>
(ReturnStmt 0x27f1a90 <col:3, col:10>
(IntegerLiteral 0x27f1a70 col:10 ‘int’ 1)))

;
struct Foo {
struct Foo;
};
template int bar(const Foo<T, Tock> &x) (CompoundStmt 0x27f45d0 <ast_demo.cpp:21:1, col:13>
(ReturnStmt 0x27f45b0 <col:3, col:10>
(IntegerLiteral 0x27f4590 col:10 ‘int’ 1)))

;
template int foo(const Tick &tag) (CompoundStmt 0x27f7278 <ast_demo.cpp:25:1, line:28:1>
(DeclStmt 0x27f62b8 <line:26:3, col:20>
0x27f5d60 “Foo<int, Tick> x =
(CXXConstructExpr 0x27f6288 col:19 ‘Foo<int, struct Tick>’:‘struct Foo<int, struct Tick>’‘void (void) throw()’)”)
(ReturnStmt 0x27f7258 <line:27:3, col:15>
(CallExpr 0x27f7210 <col:10, col:15> ‘int’
(ImplicitCastExpr 0x27f71f8 col:10 ‘int (*)(const Foo<int, struct Tick> &)’
(DeclRefExpr 0x27f7170 col:10 ‘int (const Foo<int, struct Tick> &)’ lvalue Function 0x27f7060 ‘bar’ ‘int (const Foo<int, struct Tick> &)’ (FunctionTemplate 0x27f1a20 ‘bar’)))
(ImplicitCastExpr 0x27f7240 col:14 ‘const Foo<int, struct Tick>’:‘const struct Foo<int, struct Tick>’ lvalue
(DeclRefExpr 0x27f6d80 col:14 ‘Foo<int, struct Tick>’:‘struct Foo<int, struct Tick>’ lvalue Var 0x27f5d60 ‘x’ ‘Foo<int, struct Tick>’:‘struct Foo<int, struct Tick>’)))))

template int foo(const TSpec &tag) (CompoundStmt 0x27f4c48 <ast_demo.cpp:25:1, line:28:1>
(DeclStmt 0x27f4b58 <line:26:3, col:20>
0x27f4b00 “Foo<int, TSpec> x”)
(ReturnStmt 0x27f4c28 <line:27:3, col:15>
(CallExpr 0x27f4bf8 <col:10, col:15> ‘’
(UnresolvedLookupExpr 0x27f4b70 col:10 ‘’ lvalue (ADL) = ‘1’ 0x27f4540 0x27f1a20)
(DeclRefExpr 0x27f4bd0 col:14 ‘Foo<int, TSpec>’ lvalue Var 0x27f4b00 ‘x’ ‘Foo<int, TSpec>’))))

;
int main() (CompoundStmt 0x27f5b20 <ast_demo.cpp:31:1, col:23>
(ReturnStmt 0x27f5b00 <col:3, col:20>
(CallExpr 0x27f5aa0 <col:10, col:20> ‘int’
(ImplicitCastExpr 0x27f5a88 col:10 ‘int (*)(const struct Tick &)’
(DeclRefExpr 0x27f5a00 col:10 ‘int (const struct Tick &)’ lvalue Function 0x27f58f0 ‘foo’ ‘int (const struct Tick &)’ (FunctionTemplate 0x27f4880 ‘foo’)))
(MaterializeTemporaryExpr 0x27f5ae8 <col:14, col:19> ‘const struct Tick’:‘const struct Tick’ lvalue
(ImplicitCastExpr 0x27f5ad0 <col:14, col:19> ‘const struct Tick’:‘const struct Tick’
(CXXTemporaryObjectExpr 0x27f55c0 <col:14, col:19> ‘struct Tick’‘void (void) throw()’ zeroing))))))

template <typename T, typename TSpec>
struct Foo;

struct Tick {};
struct Tock {};

template
struct Foo<T, Tick>
{};

template
int bar(Foo<T, Tick> const & x)
{ return 1; }

template
struct Foo<T, Tock>
{};

template
int bar(Foo<T, Tock> const & x)
{ return 1; }

template
int foo(TSpec const & tag)
{
Foo<int, TSpec> x;
return bar(x);
}

int main()
{ return foo(Tick()); }