[cfe-dev] libclang appears to be returning incorrect CXCursor in include statement.

Josh Gray gray.josh at gmail.com
Wed Jan 8 15:03:49 PST 2014


Hello,

I think I may have hit a bug in libclang.

Given a source file, test.cpp, which contains only the following line

#include <string>

If I parse it with clang_parseTranslationUnit() using the
CXTranslationUnit_DetailedPreprocessingRecord option I find there is a
single CXCursor located in my source file with kind
CXCursor_InclusionDirective and extent of offset 0 to offset 17.

If I get a CXCursor via calls to clang_getLocationForOffset() and
clang_getCursor() for offsets 0 to 9 I get this cursor. For offsets 10 to
17 I get a CXCursor with kind CXCursor_NoDeclFound.

I would expect to get the CXCursor_InclusionDirective CXCursor for all
offsets 0 to 17. Can anyone explain why? (For include statements using ""
rather than <> the problem does not seem to occur)

See attached sample code
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140109/e641e580/attachment.html>
-------------- next part --------------
CXCursor GetCursotAt(CXTranslationUnit tu, CXFile file, unsigned offset)
{
    CXSourceLocation sl;
    sl = clang_getLocationForOffset(tu, file, offset);
    assert(!clang_equalLocations(sl, clang_getNullLocation()));
    return clang_getCursor(tu, sl); 
}

void GetCursorExtentOffsets(CXCursor cursor, unsigned* start, unsigned* end)
{
    CXSourceRange range = clang_getCursorExtent(cursor);
    CXSourceLocation loc;
    CXFile f;
    unsigned l, c, o;

    loc = clang_getRangeStart(range);   
    clang_getInstantiationLocation(loc, &f, &l, &c, &o);
    *start = o;

    loc = clang_getRangeEnd(range);
    clang_getInstantiationLocation(loc, &f, &l, &c, &o);
    *end = o;   
}

int main(int argc, const char **argv) 
{
    CXIndex idx = clang_createIndex(1, 0);
    CXTranslationUnit tu = clang_parseTranslationUnit(idx, "test.cpp", NULL, 0, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord);
    assert(tu);
    CXFile file = clang_getFile(tu, "test.cpp");
    assert(file);

    CXCursor c;
    unsigned start, end;
    unsigned testOffset;

    //Check Curosr at offset 0
    testOffset = 0;
    c = GetCursotAt(tu, file, testOffset);
    assert(!clang_equalCursors(c, clang_getNullCursor()));
    //check we have a cursor for the #include
    assert(clang_getCursorKind(c) == CXCursor_InclusionDirective);
    //check cursor covers entire range (0 -> 17)
    GetCursorExtentOffsets(c, &start, &end);
    assert(start == 0);
    assert(end == 17);

    //Check Cursor returned for offsets 1,2,3...9
    for(testOffset = 1; testOffset < 10; testOffset++)
    {
        c = GetCursotAt(tu, file, testOffset);
        assert(!clang_equalCursors(c, clang_getNullCursor()));
        //check we have a cursor for the #include
        assert(clang_getCursorKind(c) == CXCursor_InclusionDirective);
    }

    //Check Cursor at offset 9,10...17. All will return a CXCursor with kind CXCursor_NoDeclFound
    for(testOffset = 10; testOffset < 17; testOffset++)
    {
        c = GetCursotAt(tu, file, 10);
        assert(!clang_equalCursors(c, clang_getNullCursor()));
        //check we have a cursor for the #include
        //!!clang_getCursorKind(c) now returns CXCursor_NoDeclFound!!
        assert(clang_getCursorKind(c) == CXCursor_NoDeclFound);
    }
    return 0;
}


More information about the cfe-dev mailing list