ASTMatchers: isVirtual and isOverride

What I usually do is: in the callback, take the source location of the node, look at the file name, and do a regexp on the file to determine whether you want to examine the node or not.

Well, but imagine that you have a .cpp with the definition of the methods of 3 classes, for example, and you only want to match nodes of that 3 classes (definitions and declarations). Then, you know each class has its declaration in one/some of the header files included, but you don’t know a priori where they are (normally, each class has a .h file with the same name as the class, but this is not always this way, so regular expressions don’t fit this case). However, you may have some other header files with other classes that you don’t want to match. How can I manage this? I know this is maybe a “extreme” case, but I think it’s important to me. This is why I insist.

What you can do, as Manuel suggested, is to perform the check in the callback. The SourceManager classs has various methods that are available for you to figure out where exactly a given SourceLocation is, and we’ve already mentioned several of them. I suggest you read through the documentation to find out what’s the best way to do what you’re trying to do.

Um, maybe I could firstly look for the classes’ names in the main file and then look for the location of their declarations so I was able to know which of the header files interest to me. Or do you think this is a though job?

The functionDecl() matcher in itself will match any FunctionDecl nodes, regardless of whether it is a definition or only a declaration. In addition, there is a method called FunctionDecl :: isDefinition, which also gives you the FunctionDecl object that represents the definition belonging to the current declaration.
Now I think the simplest solution would be to create a matcher for this, that would allow you to express constraints on the actual definition of the function, and then you’d be able to modify your existing matcher expression to accommodate for this.

I can’t find FunctionDecl :: isDefinition, but isDefined or TagTypeLoc:: isDefinition (I suppose you refer to this latter) , but these methods don’t give you the object that represents the definition belonging to the current declaration, just tell you if they are defitions as well, am I right?

If you are sure that all declarations of the constructor will be visible where it is implemented, you can match for the non-trivial default constructor, and then go backwards to all the decls you see from that TU.
If this is not true in your case (which in this example shouldn’t happen, I think), you can always output:
a) for all destructors, all declarations / definitions
b) for all non-trivial destructors, the fact that they’re non-trivial
Then you merge this information in a post-processing step. Things like this are quite common, which is why we’ve put together a MapReduce pipeline to support that kind of operation at a large scale, but for smaller code bases you can do something with a simple text format

Sorry, but I can’t follow you here. I’m not able to understand your explanation.

Regards,

Pedro.

El dia 24 abr 2013 11:14, Gábor Kozár kozargabor@gmail.com escribió:

What I usually do is: in the callback, take the source location of the
node, look at the file name, and do a regexp on the file to determine
whether you want to examine the node or not.

Well, but imagine that you have a .cpp with the definition of the methods
of 3 classes, for example, and you only want to match nodes of that 3
classes (definitions and declarations). Then, you know each class has its
declaration in one/some of the header files included, but you don't know a
priori where they are (normally, each class has a .h file with the same
name as the class, but this is not always this way, so regular expressions
don't fit this case). However, you may have some other header files with
other classes that you don't want to match. How can I manage this? I know
this is maybe a "extreme" case, but I think it's important to me. This is
why I insist.

What you can do, as Manuel suggested, is to perform the check in the
callback. The SourceManager classs has various methods that are available
for you to figure out where exactly a given SourceLocation is, and we've
already mentioned several of them. I suggest you read through the
documentation to find out what's the best way to do what you're trying to
do.

Um, maybe I could firstly look for the classes' names in the main file and
then look for the location of their declarations so I was able to know
which of the header files interest to me. Or do you think this is a though
job?

The functionDecl() matcher in itself will match any FunctionDecl nodes,
regardless of whether it is a definition or only a declaration. In
addition, there is a method called FunctionDecl :: isDefinition, which also
gives you the FunctionDecl object that represents the definition belonging
to the current declaration.
Now I think the simplest solution would be to create a matcher for this,
that would allow you to express constraints on the actual definition of the
function, and then you'd be able to modify your existing matcher expression
to accommodate for this.

I can't find FunctionDecl :: isDefinition, but isDefined or TagTypeLoc::
isDefinition (I suppose you refer to this latter) , but these methods don't
give you the object that represents the definition belonging to the current
declaration, just tell you if they are defitions as well, am I right?

If you are sure that all declarations of the constructor will be visible
where it is implemented, you can match for the non-trivial default
constructor, and then go backwards to all the decls you see from that TU.
If this is not true in your case (which in this example shouldn't happen,
I think), you can always output:
a) for all destructors, all declarations / definitions
b) for all non-trivial destructors, the fact that they're non-trivial
Then you merge this information in a post-processing step. Things like
this are quite common, which is why we've put together a MapReduce pipeline
to support that kind of operation at a large scale, but for smaller code
bases you can do something with a simple text format

Sorry, but I can't follow you here. I'm not able to understand your
explanation.

This is not really an explanation, but a follow-up to your real case: if
you want to delete only non-trivial methods, aren't all methods
automatically non-trivial once they're user-defined?

Cheers,
/Manuel

Hi,

Um, maybe I could firstly look for the classes’ names in the main file and then look for the location of their declarations so I was able to know which of the header files interest to me. Or do you think this is a though job?

Unfortunately, class declarations and class definitions (including method definitions) can be anywhere, regardless of whether that file is a header file or not (e.g. when templates are considered, or when a class is considered an implementation detail, etc.). Also unless you’re working in a very anti-oop environment, I think it is a safe bet that all files will usually contain classes - or if not, then they are very small, and don’t have a considerable impact on performance. So I think you can’t do much better than filtering out only the system header files.

I can’t find FunctionDecl :: isDefinition, but isDefined or TagTypeLoc:: isDefinition (I suppose you refer to this latter) , but these methods don’t give you the object that represents the definition belonging to the current declaration, just tell you if they are defitions as well, am I right?

Sorry, what I meant was FunctionDecl :: isDefined (http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html#a4a68908ca34bfedaaf8b0a80d865f54f).

If you are sure that all declarations of the constructor will be visible where it is implemented, you can match for the non-trivial default constructor, and then go backwards to all the decls you see from that TU.

I think what Manuel means - and which is a very good point by the way - is that it’s possible that a class or method was declared multiple times, because C++ allows this. (Of course, it still needs to have at most one definition.) You can handle this by going through the declaration chain using FunctionDecl :: getPreviousDecl (http://clang.llvm.org/doxygen/classclang_1_1Redeclarable.html#ae865b5549d99099ecb62d8b3a104f033).

Otherwise, in less well-behaving cases (which is usually what you want to be prepared for) you might need to perform the work in two steps: first, gather all constructor declarations (ideally some kind map, where the key is a constructor definition, and the value is a list of declarations belonging to that definition) that are potentially of interest to you, and in the second step iterate through the gathered declarations, and you should be able to make the final decision based on that collected data (since you’ll have all definitions and declarations gathered).

(Sorry for going over your head, Manuel!)

Gabor

Hi,

> *Um, maybe I could firstly look for the classes' names in the main file
and then look for the location of their declarations so I was able to know
which of the header files interest to me. Or do you think this is a though
job?*

Unfortunately, class declarations and class definitions (including method
definitions) can be anywhere, regardless of whether that file is a header
file or not (e.g. when templates are considered, or when a class is
considered an implementation detail, etc.). Also unless you're working in a
very anti-oop environment, I think it is a safe bet that all files will
usually contain classes - or if not, then they are very small, and don't
have a considerable impact on performance. So I think you can't do much
better than filtering out only the system header files.

> *I can't find FunctionDecl :: isDefinition, but isDefined or
TagTypeLoc:: isDefinition (I suppose you refer to this latter) , but these
methods don't give you the object that represents the definition belonging
to the current declaration, just tell you if they are defitions as well, am
I right?*

Sorry, what I meant was FunctionDecl :: isDefined (
http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html#a4a68908ca34bfedaaf8b0a80d865f54f
).

> *If you are sure that all declarations of the constructor will be
visible where it is implemented, you can match for the non-trivial default
constructor, and then go backwards to all the decls you see from that TU.

*
I think what Manuel means - and which is a very good point by the way - is
that it's possible that a class or method was declared multiple times,
because C++ allows this. (Of course, it still needs to have at most one
definition.) You can handle this by going through the declaration chain
using FunctionDecl :: getPreviousDecl (
http://clang.llvm.org/doxygen/classclang_1_1Redeclarable.html#ae865b5549d99099ecb62d8b3a104f033
).

Otherwise, in less well-behaving cases (which is usually what you want to
be prepared for) you might need to perform the work in two steps: first,
gather all constructor declarations (ideally some kind map, where the key
is a constructor definition, and the value is a list of declarations
belonging to that definition) that are potentially of interest to you, and
in the second step iterate through the gathered declarations, and you
should be able to make the final decision based on that collected data
(since you'll have all definitions and declarations gathered).

That's pretty much what I meant (but was unable to explain well enough :),
apart from that I'd also build up a map where the key is the constructor
definition and the value is "is this interesting".

(Sorry for going over your head, Manuel!)

Never worry about that! :slight_smile: My head is very small ...

And btw thanks a lot for all the great user support you're giving here!

Cheers,
/Manuel