<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/121502>121502</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
Missing children of class cursor underlying a typedef when instantiated from a template
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
trelau
</td>
</tr>
</table>
<pre>
I'm using the Python bindings to libclang to build a tool to create pybind11 bindings from c++ header files. Everything is pretty straightforward except when dealing with classes derived from template instantiations. I recently did a test using RecursiveASTVisitor to see if what is parsed (or accessible) between this and libclang.
Given a simple header file:
```c++
template<typename T>
class MyTemplate {
public:
T MethodA();
void MethodB(T);
T MethodC(T);
};
typedef MyTemplate<int> MyTemplateOfInt;
void Foo() {
MyTemplateOfInt();
};
```
**Using libclang (via Python)**
Used the following to get the underlying class declaration and iterate over the children:
```python
print(f'Typedef: {cursor.displayname}')
class_cursor = cursor.underlying_typedef_type.get_canonical().get_declaration()
print(f'-- Class: {class_cursor.displayname} (is definition: {class_cursor.is_definition()})')
print(f'-- Type: {class_cursor.type.spelling}')
for child in class_cursor.get_children():
print(f'---- {child.kind}: {child.displayname}')
```
The results are:
```
Typedef: MyTemplateOfInt
-- Class: MyTemplate<int> (is definition: True)
-- Type: MyTemplate<int>
```
The underlying class declaration is found but no children are present (i.e., the methods are not visited).
**Using RecursiveASTVisitor**
I override `VisitTypedefDecl` and in that function I use:
```c++
auto d = decl->getUnderlyingType()->getAsCXXRecordDecl();
llvm::outs() << "-- Class: " << d->getQualifiedNameAsString() << "\n";
llvm::outs() << "-- Type: " << decl->getUnderlyingType().getAsString(pp) << "\n";
for (auto m : d->methods()) {
llvm::outs() << "---- Method: " << m->getQualifiedNameAsString() << " (Return type: " << m->getReturnType().getAsString(pp) << ")\n";
}
```
When I do this, the results for the above header are:
```
Typedef: MyTemplateOfInt
-- Class: MyTemplate
-- Type: MyTemplate<int>
---- Method: MyTemplate<int>::MethodA (Return type: int)
---- Method: MyTemplate<int>::MethodB (Return type: void)
---- Method: MyTemplate<int>::MethodC (Return type: int)
---- Method: MyTemplate<int>::MyTemplate (Return type: void)
---- Method: MyTemplate<int>::MyTemplate (Return type: void)
---- Method: MyTemplate<int>::MyTemplate (Return type: void)
---- Method: MyTemplate<int>::~MyTemplate (Return type: void)
```
You can see that the underlying methods are available and fully instantiated with the template parameters.
This is a simple case, but the the library I am trying to wrap via pybind11 makes heavy use of class templates (nested templates, etc.) and if I could just iterate through instantiated classes that would greatly simplify things.
The Python libclang bindings get me very close, but if it's not possible to match the same data as RecursiveASTVisitor via libclang, I'll likely end up writing a tool in c++ using RecursiveASTVisitor and abandoning libclang (which is fine, just seems like a bit overkill and adds complexity compared to using the Python bindings of libclang).
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzMV0uT4jgS_jXikgFh5AKKAweK6tqoQ--jh96dPXXIVhprWpYckgzjy_72jZSNMRRTW73Rh4kgAtAjM79P-RTeq4NB3LDFE1s8T0QTSus2waEWzSSzst28Mr6qoPHKHCCUCH9vQ2kNZMpIZQ4eggWtslwL2reQNUpLEBCs1fQ_dygCQt3Shfn8cq9wtoKc8SfGn6BEIdFBoTT6GXw6omtDSRqVh9phCC344IQ6lKGw7iScBPw9xzrAqUQDEoWm0ycVSsi18B49SHTqiLJTFLCqNRmijA_CBCWCssbP4BUc5miCbkGqaDj60MP9gnnjvDri9pf9P5VXwTqC5BFBFXAqRYj2CedRAuOP1oHIc_ReZRoZX0OG4YRoIJTKgzByYGrGki1Ltn9RRzQgwKuq1jhmgaXb7ghbJt2np4ol2zMWlu5CW6MRFcKepZ9Yso3Y4XO7P8NlK7pRN5lWeScT9vAZQ2nllvFHxtcspRMAAEerZL_3xPjj_mrzfGt3tcNWz_2PZEu2SCxG2lm6Uyaw9NNo7W_FKy31d6LKF2s7U3pr35we2XlReOalp4nT52t8tsEdGX88KtF7LImIh1iy_UoPRs5cWK3tSXWue8AQFxsj0emWVjs-JeZauOgx8RVVQEfk2iO6eCMvlZYOzdtXqzvdybZ2KiIpGF_tO6ZYuiXE5GPWzaTytRYtvSaB5CsyuH_Rb90ZYOkz9McvRn7riY_fswOGb7kw1qhc6I65uDbC0PN5bdN0CjtSdTZqpPbGNKJVESmFMirKu3NF-W-jA51CQrUegN0oJ07uCYqgfI2aAnxMTGFdxzsoA1dXIgXnF-l9J3r-tcrpNCqjg7PvysjoWtvL2h88yI3j7UsEh77RwYNwd-KWzlze-9a1k-2Y-Huhc4_tvWuws2bE3J3L981917-Vh8I2RkLWBDB2cG0CR6nYownRphnOGN9F969iZoj4wdgAR8qVKMn13kbnnaQ6xOVrDCmnJAJbJnG35-4Zc82WSRd-lFBFgKIxebT5FRr_bsYUTbAgY_gQ1ilLPx0wfB14iBRGT-m3tn73669fMLdORs2jDKT1sSJd6dY2wZ8TV7pj6Q4Y51dxxPl5R_aC_9EIrQqF8q-iwq3_JThy61shbLEz9PVBhUPsjPS9D3MWMQ7a6_od_RRojD9GDisgPRFM_-g9NZfkDQD_0-LptK8mN1ZXP8QSWfUFQ-MMhLcMnGV1Jz4Ona-v0FPov4mif1HT8QrSxsp-DoNzGiDC6L_I7HEo6j8zN3wg7G84vncoPlDfCtyhMqbK9Q-Lerojiqr8_yNr91PMGjVDP8OyP7W4_3xQ3o0__9s2kAsTO9uYWm_aoHGCF0ehtMg0xlxcNFq3o6YaZdeEk4Ch566FExUGdH52rkLKU6UZOt9ceKQwoqITr5ZIbZwTroVXEBUE1_Zd2smJGqitG0aKSnxHT3F2bKkQgC36unY2wBMXBj1ZN6yROgz5jMI_VpUCXiG3jZbwW-PD0OSF0tnmUF5jPM8YkaxTvHSgQUe3HSJVtBAHmAviYXIa2tNhFKLGs0KgqQdybS9UqAJUYHzlY1mtbTdZEAuVCHnHsqf2X4ogQPi7EwtxddZJgmmg0xq0-o66BTQSmhpOTgUiuB_cqKXqR7M_HoWINZEJI625bbtPpcrL2EsoE9FESj1i5aNiEJCpEKv9d6V1J0pKD7klf_hdhTb-FI6ezL4zftpiBG49m8hNKtfpWkxwM1-li8d0lSzTSbnhC87nYjlfFjx7eFgs5qvFPMmXS7nGeZrOxURteMIXyTzh8-Vi9ZDOFvwxSxGX4gGTtVgs2EOClVB6RuVtZt1horxvcDPn80XCJ1pkqH0cpDk3eIK4G4vp88Rt6NI0aw6ePSRa-eAvYoIKGjeflY8gh4ZrcOO--R_Fo4DzsBXH3yvXjOOuGPx80ji9KUOoqYgw_sL4y0GFsslmua0Yf4m1uvua1s7-hnlg_CXa7hl_6cEdN_y_AQAA___FYChn">