libclang: traversing initializers in for-range statements

Hi,

I'm trying to use libclang to parse some C++. When I parse source that includes for-range statement like:

  int main() {
      char a[1000];
      for (auto x: a) { // <--- expect to traverse reference to `a` here
      ++x;
      }
  }

I expect to traverse reference to `a` at some point, but it looks like such traversal never happens.
Am I doing something wrong or such case is not supported by libclang?

Below is the example my traversal code in Python (actually I write in C++ but situation is similar there) and its output on sample C++ source.

Thanks,
Dmitry

» cat for_range.cpp
int main() {
    char a[1000];
    for (auto x: a) {
        ++x;
    }
}

» cat traverse.py
import sys
import clang.cindex
clang.cindex.Config.set_library_path('.')

def traverse(node):
    print node.kind, node.spelling, node.location
    for c in node.get_children():
        traverse(c)

index = clang.cindex.Index.create()
tu = index.parse(sys.argv[1])
traverse(tu.cursor)

» python traverse.py for_range.cpp
CursorKind.TRANSLATION_UNIT for_range.cpp <SourceLocation file None, line 0, column 0>
CursorKind.TYPEDEF_DECL __int128_t <SourceLocation file None, line 0, column 0>
CursorKind.TYPEDEF_DECL __uint128_t <SourceLocation file None, line 0, column 0>
CursorKind.TYPEDEF_DECL __builtin_va_list <SourceLocation file None, line 0, column 0>
CursorKind.TYPE_REF __va_list_tag <SourceLocation file None, line 0, column 0>
CursorKind.FUNCTION_DECL main <SourceLocation file 'for_range.cpp', line 1, column 5>
CursorKind.COMPOUND_STMT <SourceLocation file 'for_range.cpp', line 1, column 12>
CursorKind.DECL_STMT <SourceLocation file 'for_range.cpp', line 2, column 5>
CursorKind.VAR_DECL a <SourceLocation file 'for_range.cpp', line 2, column 10>
CursorKind.INTEGER_LITERAL <SourceLocation file 'for_range.cpp', line 2, column 12>
CursorKind.CXX_FOR_RANGE_STMT <SourceLocation file 'for_range.cpp', line 3, column 5>
CursorKind.DECL_STMT <SourceLocation file 'for_range.cpp', line 3, column 18>
CursorKind.DECL_STMT <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.BINARY_OPERATOR <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.UNEXPOSED_EXPR __begin <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.DECL_REF_EXPR __begin <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.UNEXPOSED_EXPR __end <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.DECL_REF_EXPR __end <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.UNARY_OPERATOR <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.DECL_REF_EXPR __begin <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.DECL_STMT <SourceLocation file 'for_range.cpp', line 3, column 10>
CursorKind.VAR_DECL x <SourceLocation file 'for_range.cpp', line 3, column 15>
CursorKind.UNEXPOSED_EXPR <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.UNARY_OPERATOR <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.UNEXPOSED_EXPR __begin <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.DECL_REF_EXPR __begin <SourceLocation file 'for_range.cpp', line 3, column 16>
CursorKind.COMPOUND_STMT <SourceLocation file 'for_range.cpp', line 3, column 21>
CursorKind.UNARY_OPERATOR <SourceLocation file 'for_range.cpp', line 4, column 9>
CursorKind.DECL_REF_EXPR x <SourceLocation file 'for_range.cpp', line 4, column 11>

Hi,

I’m not sure if I understand your question, but it seems to me you are assuming that the range-for loop will access the values of a by reference. This is not true by default, actually. If you write

(char x: a) or (auto x: a)

x will receive a copy of an element of a each iteration. To get access by reference, just change that to:

(char& x: a) ou (auto& x: a)

As a reminder, auto never translates to a reference type automatically–you must put the &. This is true even in cases such as:
int a = 3;
int& b = a;
auto c = b; // c gets 3, but c is not a reference to a. c is just an int.

The reason for this is that all expressions that have reference type are implicitly dereferenced, so expression “b” in the third line has int type, not reference of int, because it is automatically dereferenced.

Hope that helps,

Hi, thanks for your response,

actually I’m not writing a C++ program, but want to parse it and analyze its syntax tree using libclang. And it seems like for-range part of syntax tree is completly hidden from me.

Thanks,
Dmitry