How to use clang::ast_type_traits::DynTypedNode?

Hi everyone,

There is a task when using Clang libraries which I’ve never been able to undertake. I asked some time ago, but now it seems that the libraries have changed and I would like to resume it.

I have a memberExpr object. I just want to know the class in which that memberExpr object is. For example:

class A{
protected:
int field;
};

class B: public A{

void method() {

if( field == 1 )

}

};

In this example, field is the memberExpr and what I want to know is that the memberExpr is inside class B. I know that there is a method in ASTContext called “getParents”. When using this method, I know that you’ll not always end up in a CXXRecordDecl - sometimes you’ll also end up in a CXXMethodDcl that is defined out-of-line.

I have tried with this (just an attempt…):

ArrayRef<ast_type_traits::DynTypedNode> pv = Context->getParents(member);
_CXXRecordDecl
rec;_

size_t size = pv.size();

//Retrieve the outermost parent
if(llvm::isa(pv[size-1]))
{
CXXMethodDecl* md = (CXXMethodDecl*)(pv[size-1]);
if(llvm::isa(md->getParent()))
rec = (CXXRecordDecl*)(md->getParent());
}
else
{
if(llvm::isa(pv[size-1]))
rec = (CXXRecordDecl*)(pv[size-1]);
}

The compiler gives the following error (among others):

error: cannot cast from type ‘const clang::ast_type_traits::DynTypedNode’ to pointer type 'clang::CXXMethodDecl
CXXMethodDecl
md = (CXXMethodDecl*)(pv[size-1]);
^~~~~~~~~~~~~~~~~~~~~~~~~

Am I in the right path? How can I perform the cast?

Thanks in advance.

Hi everyone,

There is a task when using Clang libraries which I’ve never been able to undertake. I asked some time ago, but now it seems that the libraries have changed and I would like to resume it.

I have a memberExpr object. I just want to know the class in which that memberExpr object is. For example:

class A{
protected:
int field;
};

class B: public A{

void method() {

if( field == 1 )

}

};

In this example, field is the memberExpr and what I want to know is that the memberExpr is inside class B. I know that there is a method in ASTContext called “getParents”. When using this method, I know that you’ll not always end up in a CXXRecordDecl - sometimes you’ll also end up in a CXXMethodDcl that is defined out-of-line.

I have tried with this (just an attempt…):

ArrayRef<ast_type_traits::DynTypedNode> pv = Context->getParents(member);
_CXXRecordDecl
rec;_

size_t size = pv.size();

//Retrieve the outermost parent
if(llvm::isa(pv[size-1]))

You’ll want to use:
if (const auto* MD = llvm::dyn_cast(pv[size-1])) {
… use MD
}

Thanks for answering, Manuel.

However, your code didn’t work:

clases_file.cpp:35:22: error: variable ‘MD’ with type 'const auto ’ has incompatible initializer of type ‘const clang::CXXMethodDecl’
if (const auto
MD = llvm::dyn_cast(pv[size-1])) {

^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I changed “CXXMethodDecl” to “CXXMethodDecl*”:

const auto* MD = llvm::dyn_cast<CXXMethodDecl*>(pv[size-1])

but it still gives a warning and an error:

In file included from /usr/lib/llvm-3.6/include/clang/Basic/LLVM.h:22:
/usr/lib/llvm-3.6/include/llvm/Support/Casting.h:292:10: warning: returning reference to local temporary object [-Wreturn-stack-address]
return isa(Val) ? cast(Val) : nullptr;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
clases_file.cpp:35:33: note: in instantiation of function template specialization 'llvm::dyn_cast<clang::CXXMethodDecl , const
clang::ast_type_traits::DynTypedNode>’ requested here
if (const auto
MD = llvm::dyn_cast<CXXMethodDecl*>(pv[size-1])) {

In file included from /usr/lib/llvm-3.6/include/clang/Basic/LLVM.h:22:
/usr/lib/llvm-3.6/include/llvm/Support/Casting.h:56:12: error: type ‘clang::CXXMethodDecl *’ cannot be used prior to ‘::’ because it has no
members
return To::classof(&Val);

^

You need to take the address of it as dyn_cast works on pointers, not references:

   if (const auto* MD = llvm::dyn_cast<CXXMethodDecl>(&pv[size-1])) {

Jon

Hi Jonathan,

Something is failing. I have this:

ArrayRef<ast_type_traits::DynTypedNode> pv = Context->getParents(*member);

size_t size = pv.size();

if(size > 0){
if (const auto* MD = llvm::dyn_cast(&pv[size-1])) {}
}

The compiler says:

/usr/lib/llvm-3.6/include/llvm/Support/Casting.h:56:24: error: cannot initialize a parameter of type ‘const clang::Decl *’ with an rvalue of
type ‘const clang::ast_type_traits::DynTypedNode *’
return To::classof(&Val);
^~~~

Oh sorry, I didn’t realize you actually have DynTypedNode. DynTypedNode has a get method to retrieve a pointer to the underlying type.

Ok, thanks. Now it compiles. However, I have the following code:

ArrayRef<ast_type_traits::DynTypedNode> pv = Context->getParents(*member);

size_t size = pv.size();

if(size > 0){
llvm::outs() << "Size: " << size << “\n”;

for(auto it: pv)
llvm::outs() << "NodeKind: " << it.getNodeKind().asStringRef() << “\n”;

if (const CXXMethodDecl* MD = (pv[size-1]).get()) {
llvm::outs() << “A method\n”;
}
}

And the output is:

Size: 1
NodeKind: ImplicitCastExprSize

Do you know why? I supposed it would be a CXXMethodDecl or a CXXRecordDecl. The code I’m using to check the program is just:

class A{
public:
int get_a(){ return a;}
private:
int a;
};

Hi again,

I think I have understood that I have to contiunue using “getParents” in a loop until reaching the outermost parent. Something like:

while ( the current node has parents){
current node = parent of the current node
}

Then, I have tried to translate this into code:

ArrayRef<ast_type_traits::DynTypedNode> pv = Context->getParents(*member);

while ( (
Context->getParents<(&pv[0])->getNodeKind()>((&p[0)->get<(&pv[0])->getNodeKind()>()
).size() > 0){
pv = Context->getParents<(&pv[0])->getNodeKind()>((&p[0)->get<(&pv[0])->getNodeKind()>();
}

The problem here is:

error: no matching member function for call to ‘get’
((&pv[size-1])->get<(&pv[size-1])->getNodeKind()>());

/usr/lib/llvm-3.6/include/clang/AST/ASTTypeTraits.h:222:12: note: candidate template ignored: invalid explicitly-specified argument for
template parameter 'T'
const T *get() const {

How can I indicate the kind of node to "get"?

Thanks.