[cfe-dev] Using libclang to inspect the AST of template arguments

Allan Nielsen a at awn.dk
Sun May 25 08:53:08 PDT 2014


Hi,

I'm trying to write a program which uses libclang to refacture some code.
To do
this I need to inspect the AST of the template arguments, but I can not
figure
out how I can build a tree from the vistor callbacks.

Here is what my test source code looks like:

    1: template<typename ...T>
    2: struct Foo {};
    3:
    4: static Foo<int, int, Foo<short, long>> foo;

When running the clang_visitChildren on this code I receive the following
callbacks:

    (SYNTAX: <PARENT-CURSOR-HASH>/<CURSOR-HASH> <FILE>:<RANGE> <KIND>
<DISPLAYNAME> <DISPLAYTYPE>)

    1/0 /tmp/test.cxx:1,1-2,14 31 Foo<T>
    0/2 /tmp/test.cxx:1,10-23 27 T type-parameter-0-0
    1/3 /tmp/test.cxx:4,1-43 9 foo Foo<int, int, Foo<short, long> >
    3/4 /tmp/test.cxx:4,8-11 45 Foo
    3/4 /tmp/test.cxx:4,22-25 45 Foo
    3/5 /tmp/test.cxx:4,40-43 103 Foo Foo<int, int, Foo<short, long> >

What confuses me is that all callbacks on line 4 has the same parent... So
how
can I build a tree of the template arguments?

Should I be using the c++ API instead of the C-API for this?

Any hints or guidance is most appreciated.

/Allan

PS: Following are the code I wrote for this experiments:

#include <map>
#include <stdio.h>
#include <iostream>
#include "clang-c/Index.h"

static std::map<unsigned, size_t> hashes;

size_t hash(const CXCursor &c) {
    unsigned h = clang_hashCursor(c);
    if (hashes.find(h) == hashes.end()) {
        size_t s = hashes.size();
        hashes[h] = s;
        return s;
    } else {
        return hashes[h];
    }
}

struct WString {
    WString(CXString s) : str(s) {}
    ~WString() { clang_disposeString(str); }
    CXString str;
};

std::ostream &operator<<(std::ostream &o, const CXString &s) {
    if (clang_getCString(s)) o << clang_getCString(s);
    return o;
}

std::ostream &operator<<(std::ostream &o, const CXSourceRange &range) {
    CXSourceLocation start = clang_getRangeStart(range);
    CXSourceLocation end = clang_getRangeEnd(range);

    CXFile file;
    unsigned start_line = 0;
    unsigned start_col = 0;
    unsigned end_line = 0;
    unsigned end_col = 0;

    clang_getExpansionLocation(start, &file, &start_line, &start_col, 0);
    clang_getExpansionLocation(end, 0, &end_line, &end_col, 0);

    o << clang_getFileName(file) << ":";
    if (start_line == end_line)
        o << start_line << "," << start_col << "-" << end_col;
    else
        o << start_line << "," << start_col << "-" << end_line << ","
          << end_col;

    return o;
}

enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent,
                              CXClientData client_data) {
    if (cursor.kind == CXCursor_MacroDefinition) return
CXChildVisit_Recurse;

    CXSourceRange range = clang_getCursorExtent(cursor);
    CXType t = clang_getCursorType(cursor);
    CXType tt = clang_getCanonicalType(t);

    std::cout << hash(parent) << "/" << hash(cursor) << " " << range << " "
              << cursor.kind << " " << clang_getCursorDisplayName(cursor)
<< " "
              << clang_getTypeSpelling(tt) << std::endl;

    return CXChildVisit_Recurse;
}

int main(int argc, char *argv[]) {
    CXIndex idx = clang_createIndex(1, 1);
    CXTranslationUnit tu = clang_createTranslationUnitFromSourceFile(
        idx, 0, argc - 1, argv + 1, 0, 0);
    clang_visitChildren(clang_getTranslationUnitCursor(tu), visit, 0);
    clang_disposeTranslationUnit(tu);
    return 0;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140525/feec1d7f/attachment.html>


More information about the cfe-dev mailing list