5

I am using the abstract syntax tree that clang provides through the python interface, trying to parse a simple structure containing a std::vector:

#include <vector>

struct outer_t
{
    std::vector<int> vec_of_ints;
};

I would like to get the template argument of the vector, but I cannot find a reference to it in the respective node of the AST. The get_num_template_arguments() member function returns -1. I therefore think that the get_template_* functions cannot be used. I tried the following:

import sys
import clang.cindex
clang.cindex.Config.set_library_file("/usr/lib/llvm-6.0/lib/libclang.so.1")

class Walker:
    def __init__(self, filename):
        self.filename = filename

    def walk(self, node):
        node_in_file =  bool(node.location.file and node.location.file.name == self.filename)
        if node_in_file:
            print(f"node.spelling = {node.spelling:14}, node.kind = {node.kind}")
            if node.kind == clang.cindex.CursorKind.TEMPLATE_REF:
                print(f"node.get_num_template_arguments = {node.get_num_template_arguments()}")
        for child in node.get_children():
            self.walk(child)

filename = sys.argv[1]
index = clang.cindex.Index.create()
translation_unit = index.parse(filename)

root = translation_unit.cursor        
walker = Walker(filename)
walker.walk(root)

This produces the following result:

node.spelling = vec_of_ints   , node.kind = CursorKind.FIELD_DECL
node.spelling = std           , node.kind = CursorKind.NAMESPACE_REF
node.spelling = vector        , node.kind = CursorKind.TEMPLATE_REF
node.get_num_template_arguments = -1

Is there another way to get the template argument or am I doing something wrong ?

1 Answer 1

4
+25

The TEMPLATE_REF cursor kind doesn't seem to have any information about its arguments, at least for this example; I don't know why. But FIELD_DECL has a type that can have template arguments. Here is a minimally modified version of your code that prints the number of template arguments for the vec_of_ints field in your example code:

import sys
import clang.cindex
clang.cindex.Config.set_library_file("/usr/lib/llvm-6.0/lib/libclang.so.1")

class Walker:
    def __init__(self, filename):
        self.filename = filename

    def walk(self, node):
        node_in_file =  bool(node.location.file and node.location.file.name == self.filename)
        if node_in_file:
            print(f"node.spelling = {node.spelling:14}, node.kind = {node.kind}")
            # -------- BEGIN modified section --------
            type = node.type
            if type is not None:
                ntargs = type.get_num_template_arguments()
                if ntargs > 0:
                    print(f"  type.spelling = {type.spelling}")
                    print(f"  type.get_num_template_arguments = {ntargs}")
            # -------- END modified section --------
        for child in node.get_children():
            self.walk(child)

filename = sys.argv[1]
index = clang.cindex.Index.create()
translation_unit = index.parse(filename)

root = translation_unit.cursor
walker = Walker(filename)
walker.walk(root)

When run on your example input file, I get:

node.spelling = outer_t       , node.kind = CursorKind.STRUCT_DECL
node.spelling = vec_of_ints   , node.kind = CursorKind.FIELD_DECL
  type.spelling = std::vector<int>
  type.get_num_template_arguments = 1
node.spelling = std           , node.kind = CursorKind.NAMESPACE_REF
node.spelling = vector        , node.kind = CursorKind.TEMPLATE_REF

I don't claim this will handle all cases of templates appearing in code. I discovered the above through a combination of trial and error and reading the clang/cindex.py library module source file. But it hopefully serves as a useful starting point.

In any case, one important thing to understand about the Clang AST (and pretty much all C/C++ ASTs) is that types are not nodes in the main syntax tree. Rather, types are semantic interpretations of some nodes in that tree, and thus sort of sit to the side. That's why they don't appear as arguments to walk.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.