Search code examples
pythonlibclang

How to retrieve function call argument values using libclang


Is it possible to retrieve the argument values of a clang.cindex.CursorKind.CALL_EXPR cursor?

When I dump the AST using the compiler (clang++ -ast-dump source.cpp) I get info about function calls (call expressions) and their arguments. But I'm not able to replicate it using the bindings for python (where the AST is retrieved using libclang's parser).

Here's the source code I'm using:

#include <iostream>
#include <GL/glut.h>
#include <EGL/egl.h>

#define MULTILINE(...) #__VA_ARGS__

void renderFunction()
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 0.0, 1.0);
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    glBegin(GL_QUADS);
        glVertex2f(-0.5, -0.5);
        glVertex2f(-0.5, 0.5);
        glVertex2f(0.5, 0.5);
        glVertex2f(0.5, -0.5);
    glEnd();
    glFlush();
}

int main(int argc, char *argv[])
{          
    glutInit(&argc, argv);       
    glutInitDisplayMode(GLUT_SINGLE);
    glutInitWindowSize(500,500);
    glutInitWindowPosition(100,100);
    glutCreateWindow("OpenGL - First window demo");
    glutDisplayFunc(renderFunction);
    glutMainLoop();    

    return 0;
}

Here's a part of its AST dump:

|   |-CallExpr 0x430b540 <line:10:5, col:32> 'void'
|   | |-ImplicitCastExpr 0x430b528 <col:5> 'void (*)(GLbitfield)' <FunctionToPointerDecay>
|   | | `-DeclRefExpr 0x430b4d0 <col:5> 'void (GLbitfield)' lvalue Function 0x3d3b060 'glClear' 'void (GLbitfield)'
|   | `-ImplicitCastExpr 0x430b570 </usr/include/GL/gl.h:691:31> 'GLbitfield':'unsigned int' <IntegralCast>
|   |   `-IntegerLiteral 0x430b4b0 <col:31> 'int' 16384

I'd like to retrieve the IntegerLiteral value part in the last line by evaluating the call expression cursor.


Solution

  • You can get this information from the list of tokens, for IntegerLiteral the first token will be your number (not really that neat but better than nothing!).

    Example cpp program:

    #define FOO 6
    
    void foo(int x) {}
    
    int main()
    {
        foo(FOO);
        return 0;
    }
    

    Example python code to parse it and print out just the IntegerLiteral value (using lib clang):

    import clang.cindex
    import sys
    
    path = '/your/path/to/libclang.so'
    clang.cindex.Config.set_library_file(path)
    
    def get_ts(source_path):
        index = clang.cindex.Index.create()
        return index.parse(source_path)
    
    def print_node(node):
        if node.kind == clang.cindex.CursorKind.INTEGER_LITERAL:
            print node.type.kind, node.get_tokens().next().spelling
        map(print_node, node.get_children())
    
    ts = get_ts('test.cpp')
    map(print_node, ts.cursor.get_children())
    

    Output:

    TypeKind.INT 6
    TypeKind.INT 0