2

Is there a way to get "base" type of, well, Type. I see that it's possible to test for const or volatile, but I don't see a way, to get the underlying type.

What I am ultimately trying to do is to map member relationships between classes, and currently it's missing some due to type A being different from const A.

The only workaround I see is to check with clang_isConstQualifiedType and parse spelling, which does not seem like a good idea.

This is the class layout that I have problem with:

class A {};

class B {
 A a;
}

class C {
  const A a;
  B* b;
}

It's hard to map C->A.

luk32
  • 15,812
  • 38
  • 62

1 Answers1

1

It appears an at least partial solution lies in the function "clang_getTypeDeclaration." Hopefully that should point you in the right direction, but I'll post some code I genned up and the results I'm getting.

// clang_fullname.cc

#include <clang-c/Index.h>

#include <iostream>

using namespace std;

/*
 * help with CXString
 */
ostream &operator<<(ostream &o, CXString cxs) {
  o << clang_getCString(cxs);
  clang_disposeString(cxs);
  return o;
}

/*
 * Display fully qualified cursor name
 */
ostream &operator<<(ostream &o, CXCursor cursor) {
  /*
   * Base of recursion
   */
  if (clang_Cursor_isNull(cursor) || clang_isTranslationUnit(cursor.kind))
    return o;

  /*
   * switching to a referenced cursor is nice for templates and function calls
   */
  CXCursor cursorReferenced = clang_getCursorReferenced(cursor);
  /*
   * Sometimes a cursorReferenced will be the same cursor, so we must avoid
   * infinite recursion
   */
  if (!clang_Cursor_isNull(cursorReferenced) &&
      !clang_equalCursors(cursor, cursorReferenced)) {
    return o << clang_getCursorReferenced(cursor);
  } else {
    /*
     * Typical recursive step
     */
    return o << clang_getCursorSemanticParent(cursor)
             << "::"
             /*
              * Here the type of the type declaration is retrieved #ugly
              */
             << clang_getTypeSpelling(clang_getCursorType(
                    clang_getTypeDeclaration(clang_getCursorType(cursor))));
  }
}

int main(int argc, char *argv[]) {
  if (argc != 4) {
    cout << "usage: filename line col" << endl;
    return 0;
  }

  CXIndex index = clang_createIndex(0, 0);
  CXTranslationUnit TU = clang_createTranslationUnitFromSourceFile(
      index, argv[1], 0, nullptr, 0, nullptr);
  CXFile cxfile = clang_getFile(TU, argv[1]);
  unsigned line = atoi(argv[2]);
  unsigned column = atoi(argv[3]);

  CXSourceLocation cxloc = clang_getLocation(TU, cxfile, line, column);
  cout << clang_getCursor(TU, cxloc) << endl;

  clang_disposeTranslationUnit(TU);
  clang_disposeIndex(index);
}

So, the program takes a filename, line number, and column, and outputs the determined type. I used the following test file:

//foo.cc

class A {};

class B {
  A a;
}

class C {
  const A a;
  B *b;
}

And ran the following command:

./clang_fullname foo.cc 10 5

(That points to the "n" in "const")

And got as output:

::C::A

I tested it on some other things, and it seems to be a "workable solution," and certainly gives me more confidence than trying to "parse out" the const qualifier manually.

NOTE: The way this is written above is somewhat dangerous. Because CXCursor is just a typedef of void*, that operator<< will eat up all void pointers sent its way. Better to wrap CXCursor in some helper class.

Nathan Chappell
  • 2,099
  • 18
  • 21