4

I have just started using libclang via python bindings. I understand that I can traverse the entire syntax tree (AST) using get_children, but I have not been able to find a get_next_sibling() (or whatever it might be called) function so that I can skip subtrees that are not of interest. Does such a function exist?

Roger House
  • 481
  • 1
  • 5
  • 12

3 Answers3

3

I don't think a get_next_sibling function exists in the Python API, but I also don't see why you should need it.

In the python API, each node in the AST knows about all its children, so that skipping uninteresting subtrees can easily be done by simply skipping them in the loop over the parent's children. Re-using an example from Eli Bendersky's excellent blog post about the libclang Python API:

def find_typerefs(node, typename):
    """ Find all references to the type named 'typename'
    """
    if node.kind.is_reference():
        ref_node = clang.cindex.Cursor_ref(node)
        if ref_node.spelling == typename:
            print 'Found %s [line=%s, col=%s]' % (
                typename, node.location.line, node.location.column)

    # Recurse for children of this node,
    # skipping all nodes not beginning with "a"
    for c in node.get_children():
        if c.spelling.startswith ("a"):
            find_typerefs(c, typename)
François Févotte
  • 19,520
  • 4
  • 51
  • 74
  • How would you skip the include of a header file e.g. from the standard library with this? I can figure out the node but I am lacking a skip function. If I skip it during the analysis after each get_children call the program will take forever. – telina Apr 11 '18 at 13:33
3

As francesco pointed out it is possible to skip elements. The mentoined code example though is not working anymore due to changes in latest cindex.py revision.

Below is a minimal example to get specific nodes from AST.

example.cpp file:

int i; 
char var[10]; 
double tmp;

int add (int a, int b)
{
  int r;
  r=a+b;
  return (r);
}

example python code:

import sys
from clang.cindex import *

index = Index.create()
tu = index.parse('example.cpp')

root_node = tu.cursor

#for further working with children nodes i tend to save them in a seperate list
#wanted nodes in extra list "result"
wanted_nodes = ['var', 'tmp']
result = []
node_list= []

for i in node.get_children():
    node_list.append(i)

for i in node_list:
    if i.spelling in wanted_nodes:
        result.append(i)

#now result contains the two nodes "var" and "add"

#print the name
for i in result:
    print i.spelling

#print the type
for i in result:
    print i.type.kind

######OUTPUT#######
>>> var
>>> add
>>> TypeKind.CONSTANTARRAY
>>> TypeKind.DOUBLE

if you want furthermore the type of each element of the array u get it through:

result[1].type.element_type.kind

#######OUTPUT######
>>> TypeKind.CHAR_S

since the modul cindex.py is well documented it shouldnt be hard to find how to get the information that you need.

Ben
  • 783
  • 7
  • 13
-1

In terms of clang-c, enum CXChildVisitResult have 3 values, and CXChildVisit_Continue skips visiting children, so visitor comes to next sibling. Something like that should be in python too.

Sergey Shambir
  • 1,562
  • 12
  • 12