CXCursor API questions

Hello,

I'm trying to traverse a translation unit by means of CLang's CXCursor API (libclang), and I have run into a couple of questions. Consider the following code:

class Translator
{
public:
   ...
   void translate()
   {
       clang_visitChildren(clang_getTranslationUnitCursor(tu_), &Translator::visit, this);
   }

private:

   static void visit(CXCursor cursor, CXCursor parent, CXClientData data)
   {
     CXCursor lex_parent = clang_getCursorLexicalParent(cursor);

     ...
     return CXChildVisit_Continue;
   }
};

I.e., I'm attempting to translate the AST clang generates into my own representation using a "Translator" object, but have some difficulties since the arguments the above "Translator::visit" callback is being called with don't seem to correspond to the CLang documentation:

1) The documentation suggests that 'parent' should correspond to the parent cursor of 'cursor'. However, I find that 'parent' and 'lex_parent' don't (ever !) compare equal. Shouldn't they ?

2) The documentation suggests that the parent cursor of a global declaration is the translation unit. However, in case where 'cursor' corresponds in fact to global declarations in my source file, 'lex_parent' is an 'unexposed' cursor (and isn't equal to 'parent', which always is the translation unit). What is wrong ? (And, how can I distinguish declarations in my source files from builtin declarations, such as __builtin_va_list ?)

3) I notice a strange ordering of during the cursor traversal: It starts with some builtin items (such as __builtin_va_list), followed by my own declarations, followed by other builtin items (macros such as __clang__). Shouldn't my own declarations come last ?

Am I doing something wrong, or have I run into libclang bugs ?

And finally:

How can I translate a cursor into a file location ? I see how to generate a CXSourceLocation, but that is an opaque type. What function should I use to query the (filename, linenum, column) triplet ?

Any help is much appreciated !

Thanks,
         Stefan

Hi Stefan,

Hello,

I'm trying to traverse a translation unit by means of CLang's CXCursor
API (libclang), and I have run into a couple of questions. Consider the
following code:

class Translator
{
public:
  ...
  void translate()
  {
      clang_visitChildren(clang_getTranslationUnitCursor(tu_),
&Translator::visit, this);
  }

private:

  static void visit(CXCursor cursor, CXCursor parent, CXClientData data)
  {
    CXCursor lex_parent = clang_getCursorLexicalParent(cursor);

    ...
    return CXChildVisit_Continue;
  }
};

I.e., I'm attempting to translate the AST clang generates into my own
representation using a "Translator" object, but have some difficulties
since the arguments the above "Translator::visit" callback is being
called with don't seem to correspond to the CLang documentation:

1) The documentation suggests that 'parent' should correspond to the
parent cursor of 'cursor'. However, I find that 'parent' and
'lex_parent' don't (ever !) compare equal. Shouldn't they ?

I doubt that they "never" compare equal. They won't compare equal within function bodies (or other expressions) for reasons that are relatively hard to fix, i.e., we don't keep parent pointers for statements or expressions.

2) The documentation suggests that the parent cursor of a global
declaration is the translation unit. However, in case where 'cursor'
corresponds in fact to global declarations in my source file,
'lex_parent' is an 'unexposed' cursor (and isn't equal to 'parent',
which always is the translation unit). What is wrong ? (And, how can I
distinguish declarations in my source files from builtin declarations,
such as __builtin_va_list ?)

A bug, perhaps?

3) I notice a strange ordering of during the cursor traversal: It starts
with some builtin items (such as __builtin_va_list), followed by my own
declarations, followed by other builtin items (macros such as
__clang__). Shouldn't my own declarations come last ?

I could certainly see a case for visiting macro definitions and instantiations before declarations, since preprocessing theoretically happens in an earlier phase of translation. But, otherwise, libclang sounds like it's doing the same thing.

And finally:

How can I translate a cursor into a file location ? I see how to
generate a CXSourceLocation, but that is an opaque type. What function
should I use to query the (filename, linenum, column) triplet ?

It's all here:

  http://clang.llvm.org/doxygen/group__CINDEX__LOCATIONS.html

  - Doug

1) The documentation suggests that 'parent' should correspond to the
parent cursor of 'cursor'. However, I find that 'parent' and
'lex_parent' don't (ever !) compare equal. Shouldn't they ?

I doubt that they "never" compare equal. They won't compare equal within function bodies (or other expressions) for reasons that are relatively hard to fix, i.e., we don't keep parent pointers for statements or expressions.

OK. Sorry for being sloppy. I meant to say that I experimented a little with simple C++ code, and in doing that I couldn't ever get a case where the parent cursor (in a visitor callback) matched the lexical parent of the visited cursor. (Note that I was focusing on declarations, and thus didn't even dive into statements and expressions at all.)

2) The documentation suggests that the parent cursor of a global
declaration is the translation unit. However, in case where 'cursor'
corresponds in fact to global declarations in my source file,
'lex_parent' is an 'unexposed' cursor (and isn't equal to 'parent',
which always is the translation unit). What is wrong ? (And, how can I
distinguish declarations in my source files from builtin declarations,
such as __builtin_va_list ?)

A bug, perhaps?

That's what I thought, but wasn't bold enough to assume. I can certainly file an issue for that.

3) I notice a strange ordering of during the cursor traversal: It starts
with some builtin items (such as __builtin_va_list), followed by my own
declarations, followed by other builtin items (macros such as
__clang__). Shouldn't my own declarations come last ?

I could certainly see a case for visiting macro definitions and instantiations before declarations, since preprocessing theoretically happens in an earlier phase of translation. But, otherwise, libclang sounds like it's doing the same thing.

OK, true.

Thanks,
         Stefan