C++ libclang: Retrieving cursor from CXSourceLocation returning wrong cursor?

泄露秘密 提交于 2020-01-13 03:56:50

问题


I am currently writing a simple clone detector using libclang with C++.

The program stores cursors using a struct, containing a pointer to the translation unit and the CXSourceLocation gained from calling clang_getCursorLocation(cursor).

typedef struct {
    CXTranslationUnit* tu;
    CXSourceLocation srcLoc;
} t_cursorLocation;

For the sake of this error, the child visitor function visits each node and creates a struct from each cursor. With a struct of type t_cursorLocation, I wrote this function to retrieve the corresponding cursor:

CXCursor getCursor(t_cursorLocation *loc1) {
    return clang_getCursor(*loc1->tu, loc1->srcLoc);
}

However, with some cursors, when I create the t_cursorLocation struct and use it to retrieve the cursor from which is was created, the retrieved cursor does not equal the cursor from which it originated. As an example, see the child visitor function:

CXChildVisitResult traverseAST(CXCursor cursor, CXCursor parent,
                                                CXClientData client_data) {
    CXTranslationUnit tu = clang_Cursor_getTranslationUnit(cursor);
    CXTranslationUnit tu2 = *((CXTranslationUnit *) client_data);

    t_cursorLocation *loc = new t_cursorLocation();
    loc->tu = &tu;
    loc->srcLoc = clang_getCursorLocation(cursor);

    CXCursor c2 = getCursor(loc);
    printf("CursorKind\t%s\n",
           clang_getCString(clang_getCursorKindSpelling(cursor.kind)));
    if (clang_equalCursors(cursor, c2)) {
        printf("Noooo - the cursors do not match! Next test.....");
        // use translation unit passed as client_data to see if
        // there's a difference
        loc->tu = &tu2;
        c2 = getCursor(loc);
        if (clang_equalCursors(cursor, c2)) {
            printf("FAILED ALSO!\n");
        } else {
            printf("PASSED???\n");
        }
    } else {
        printf("We have a match!\n");
    }
    return CXChildVisit_Recurse;
}

My main function is as follows:

int main(int argc, char **argv) {
    CXIndex index = clang_createIndex(0, 0);
    // initialise the translation unit
    CXTranslationUnit tu = clang_parseTranslationUnit(index, 0,
        argv, argc, 0, 0, CXTranslationUnit_None);

    // set the client data in traverseAST
    CXClientData data = &tu;// NULL;
    // get the root cursor for the translation unit
    CXCursor rootCursor = clang_getTranslationUnitCursor(tu);
    clang_visitChildren(rootCursor, traverseAST, data);

    clang_disposeTranslationUnit(tu);
    clang_disposeIndex(index);

    return 0;
}

The dummy source code I ran this on is as follows:

void goo() {
    // nothing here
}

void foo() {
    // do something
    int a;
    switch (a) {
        case 0:
            goo();
    };
}

However the output is consistent, which suggests that this only happens with certain cursor kinds.

Is this a bug or is there something I am missing or doing wrong?

Thanks in advance, Jacob


回答1:


Either I'm missing your point entirely, or you are using clang_equalCursors the wrong way: when both cursors are equals, clang_equalCursors returns a non-zero value. Which means I think you're testing cursors inequalities instead of equalities.

Now, let me try to explain why certain cursors apparently behave differently than others. Each cursor has only one source location. However, there might be several cursors at the same source location. Think for example about the following line:

CXIndex index = clang_createIndex(0, 0);
//      ^

There should be at least two cursors at the marked position above:

  1. VarDecl: index
  2. DeclRefExpr: index = clang_createIndex(0,0)

When you convert the source location back to a cursor, clang_getCursor gives you the most specific one (the variable declaration in this case). I suspect this is what happens to you in this case: getCursor(loc) only gives you back the cursor that you are visiting if it is the most specific at its location.

Try printing the physical source location of each cursor (using for example clang_getCursorExtent and clang_getExpansionLocation) to understand what happens.



来源:https://stackoverflow.com/questions/15346521/c-libclang-retrieving-cursor-from-cxsourcelocation-returning-wrong-cursor

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!