doing global unused methods analysis

Hi

I'm working on the LibreOffice team, and I'm using a clang plugin to do a fairly brute-force analysis looking for unused methods, using the clang compiler plugin API.

Mostly this works fairly well. I'm walking the AST and outputting every method definition I see, and every call I see.

The one shortcoming is that clang does not generate AST nodes for all implicit instantiations of templates.
For example, if I have
    template<T> class A {};
    template<T> class B {};
    class C : public A< B<int> > {};
, it will not generate AST nodes for the B<int> instantiation that occurs in the template parameter.

Is there a way to make clang do this, or am I simply barking up the wrong tree :slight_smile: ?

Thanks, Noel Grandin.

Looks to me like everything is in the AST:

$ cat /tmp/t.cc
template class A {};
template class B {};
class C : public A<B>{};

$ clang-query /tmp/t.cc – -std=c++11

clang-query> m cxxRecordDecl()

Match #1:

Binding for “root”:
CXXRecordDecl 0x32ec0c0 </tmp/t.cc:1:23, col:32> col:29 class A definition
`-CXXRecordDecl 0x3339180 <col:23, col:29> col:29 implicit class A

Match #2:

Binding for “root”:
CXXRecordDecl 0x3339180 </tmp/t.cc:1:23, col:29> col:29 implicit class A

Match #3:

Binding for “root”:
ClassTemplateSpecializationDecl 0x33398f8 </tmp/t.cc:1:1, col:32> col:29 class A definition

-TemplateArgument type ‘class B’
`-CXXRecordDecl 0x3339ad8 prev 0x33398f8 <col:23, col:29> col:29 implicit class A

Match #4:

Binding for “root”:
CXXRecordDecl 0x3339ad8 prev 0x33398f8 </tmp/t.cc:1:23, col:29> col:29 implicit class A

Match #5:

Binding for “root”:
CXXRecordDecl 0x3339290 </tmp/t.cc:2:23, col:32> col:29 class B definition
`-CXXRecordDecl 0x3339598 <col:23, col:29> col:29 implicit class B

Match #6:

Binding for “root”:
CXXRecordDecl 0x3339598 </tmp/t.cc:2:23, col:29> col:29 implicit class B

Match #7:

Binding for “root”:
ClassTemplateSpecializationDecl 0x3339750 </tmp/t.cc:2:1, col:32> col:29 class B
`-TemplateArgument type ‘int’

Match #8:

Binding for “root”:
CXXRecordDecl 0x3339628 </tmp/t.cc:3:1, col:28> col:7 class C definition

-public ‘A<B >’:‘class A<class B >’
`-CXXRecordDecl 0x3339b98 <col:1, col:7> col:7 implicit class C

Match #9:

Binding for “root”:
CXXRecordDecl 0x3339b98 </tmp/t.cc:3:1, col:7> col:7 implicit class C

Hi Manuel

That was a bad example, this is a better one (dramatically simplified from my actual code).
I can't seem to use clang-query here (I have 3.6), but dumping the AST shows my problem.

Specifically, in the below code, when I traverse the AST, there is no way to see that a call to doRegisterHandlers() is in fact being generated.

The relevant section of AST looks like:
CallExpr 0x328d958 <line:15:9, col:42> '<dependent type>'

> > > >-CXXDependentScopeMemberExpr 0x328d8d8 <col:9, col:15> '<dependent type>' lvalue
> > > > `-CXXThisExpr 0x328d8c0 <col:9> 'ImportFilterImpl<Generator> *' this
> > > `-DeclRefExpr 0x328d930 <col:34> 'Generator' lvalue Var 0x328d850 'exporter' 'Generator'

Now I know that clang is doing the right thing here, but I'm hoping there is a way I can tell it to "expand out" and generate more AST nodes when I hit a template instantiation?

Thanks a lot for the help!

Regards, Noel.

Hi Manuel

That was a bad example, this is a better one (dramatically simplified from my actual code).
I can’t seem to use clang-query here (I have 3.6), but dumping the AST shows my problem.

Note that the AST dump doesn’t contain all nodes.
In this case, it is correct though. The problem is that the method is not actually instantiated. You’ll need to reference it in order for it to actually get instantiated.

Hi

You are correct, and doing an --ast-dump dump of my actual code reveals that the CallExpr node I want is there (under a ClassTemplateSpecializationDecl node).
Now I just need to figure out why my VisitCallExpr method is not being called.

Thanks for the help.

Regards, Noel.

Note that the AST dump doesn’t contain all nodes.
In this case, it is correct though. The problem is that the method is not actually instantiated. You’ll need to
reference it in order for it to actually get instantiated.

Hi

You are correct, and doing an --ast-dump dump of my actual code reveals that the CallExpr node I want is there (under a
ClassTemplateSpecializationDecl node).
Now I just need to figure out why my VisitCallExpr method is not being called.

Btw, I think looking into the AST matchers and clang-query can greatly speed up your development cycle here. We have a dead code analysis based on these, and I wouldn’t want to implement all the matchers with special visitors.

Sounds interesting, I'll have to look into those. At the moment we have a framework based around RecursiveASTVisitor, so there is not that much code to implement in each checker (of which we have lots).

Found my problem.... a little thing called:
    bool shouldVisitTemplateInstantiations () const
from here:
    http://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html

Sigh, now to strip out all the junk I added trying to workaround my lack of documentation reading :slight_smile:

-- Noel Grandin.

OT: Did anyone notice that the class description (“This class performs three distinct tasks … By default, this visitor …”) appears twice in that HTML page? Something appears to have gone wrong with Doxygen.