title: Parsing namespaces with clang: AST differences in when including a header in another source file or parsing it directly
body: <p>Sorry for the verbose question, but I can't see any other way to make it clear.  I am writing a tool to transform C++ header files to SWIG interface files as a starter for further fine-tuning.</p>
  
  <p>In the process of doing this, I've noticed some strange behavior by clang (v3.0).  If I parse the header file I get a significantly different AST than if I parse a source file that includes the header.</p>
  
  <p>For purposes of illustration, here are some sample source files:</p>
  
  <p>Source file:</p>
  
  <pre><code>// example.cpp: Test case for nsbug.py
  //
  #include "example.h"
  </code></pre>
  
  <p>Header:</p>
  
  <pre><code>// example.h: Test case for nsbug.py
  //
  namespace Geom {
  
  struct Location
  {
      double x, y;
  };
  
  class Shape
  {
  public:
      Shape();
  
      void set_location(const Location &amp;where)
      {
          m_pos = where;
      };
  
      const Location &amp;get_location() const
  
      // Draw it...
      virtual void draw() const = 0;
  
  protected:
      Location m_pos;
  };
  
  class Circle : public Shape
  {
      Circle();
  
      virtual void draw() const;
  };
  } // namespace Geom
  </code></pre>
  
  <p>I've used the following Python code to parse it and dump the AST:</p>
  
  <pre><code># Usage: python nsbug.py &lt;file&gt;
  
  import sys
  import clang.cindex
  
  def indent(level):
      """ Indentation string for pretty-printing
      """ 
      return '  '*level
  
  def output_cursor(cursor, level):
      """ Low level cursor output
      """
      spelling = ''
      displayname = ''
  
      if cursor.spelling:
          spelling = cursor.spelling
      if cursor.displayname:
          displayname = cursor.displayname
      kind = cursor.kind;
  
      print indent(level) + spelling, '&lt;' + str(kind) + '&gt;'
      print indent(level+1) + '"'  + displayname + '"'
  
  def output_cursor_and_children(cursor, level=0):
      """ Output this cursor and its children with minimal formatting.
      """
      output_cursor(cursor, level)
      if cursor.kind.is_reference():
          print indent(level) + 'reference to:'
          output_cursor(clang.cindex.Cursor_ref(cursor), level+1)
  
      # Recurse for children of this cursor
      has_children = False;
      for c in cursor.get_children():
          if not has_children:
              print indent(level) + '{'
              has_children = True
          output_cursor_and_children(c, level+1)
  
      if has_children:
          print indent(level) + '}'
  
  index = clang.cindex.Index.create()
  tu = index.parse(sys.argv[1], options=1)
  
  output_cursor_and_children(tu.cursor)
  </code></pre>
  
  <p>When I run this on <em>example.cpp</em> I get (correctly I think):</p>
  
  <pre><code> &lt;CursorKind.TRANSLATION_UNIT&gt;
    "example.cpp"
  {
  
    (Deleted lots of clang-generated declarations such as __VERSION__)
  
    Geom &lt;CursorKind.NAMESPACE&gt;
      "Geom"
    {
      Location &lt;CursorKind.STRUCT_DECL&gt;
        "Location"
      {
        x &lt;CursorKind.FIELD_DECL&gt;
          "x"
        y &lt;CursorKind.FIELD_DECL&gt;
          "y"
      }
      Shape &lt;CursorKind.CLASS_DECL&gt;
        "Shape"
      {
         &lt;CursorKind.CXX_ACCESS_SPEC_DECL&gt;
          ""
         &lt;CursorKind.CXX_ACCESS_SPEC_DECL&gt;
          ""
        Shape &lt;CursorKind.CONSTRUCTOR&gt;
          "Shape()"
        set_location &lt;CursorKind.CXX_METHOD&gt;
          "set_location(const Geom::Location &amp;)"
        {
          where &lt;CursorKind.PARM_DECL&gt;
            "where"
          {
             &lt;CursorKind.TYPE_REF&gt;
              "struct Geom::Location"
            reference to:
              Location &lt;CursorKind.STRUCT_DECL&gt;
                "Location"
          }
           &lt;CursorKind.COMPOUND_STMT&gt;
            ""
          {
             &lt;CursorKind.CALL_EXPR&gt;
              "operator="
            {
               &lt;CursorKind.MEMBER_REF_EXPR&gt;
                "m_pos"
               &lt;CursorKind.UNEXPOSED_EXPR&gt;
                "operator="
              {
                 &lt;CursorKind.DECL_REF_EXPR&gt;
                  "operator="
              }
               &lt;CursorKind.DECL_REF_EXPR&gt;
                "where"
            }
          }
        }
        get_location &lt;CursorKind.CXX_METHOD&gt;
          "get_location()"
        {
           &lt;CursorKind.TYPE_REF&gt;
            "struct Geom::Location"
          reference to:
            Location &lt;CursorKind.STRUCT_DECL&gt;
              "Location"
        }
         &lt;CursorKind.CXX_ACCESS_SPEC_DECL&gt;
          ""
         &lt;CursorKind.CXX_ACCESS_SPEC_DECL&gt;
          ""
        m_pos &lt;CursorKind.FIELD_DECL&gt;
          "m_pos"
        {
           &lt;CursorKind.TYPE_REF&gt;
            "struct Geom::Location"
          reference to:
            Location &lt;CursorKind.STRUCT_DECL&gt;
              "Location"
        }
      }
      Circle &lt;CursorKind.CLASS_DECL&gt;
        "Circle"
      {
         &lt;CursorKind.CXX_BASE_SPECIFIER&gt;
          "class Geom::Shape"
        reference to:
          Shape &lt;CursorKind.CLASS_DECL&gt;
            "Shape"
        {
           &lt;CursorKind.TYPE_REF&gt;
            "class Geom::Shape"
          reference to:
            Shape &lt;CursorKind.CLASS_DECL&gt;
              "Shape"
        }
        Circle &lt;CursorKind.CONSTRUCTOR&gt;
          "Circle()"
        draw &lt;CursorKind.CXX_METHOD&gt;
          "draw()"
      }
    }
  }
  </code></pre>
  
  <p>But when I try it on the header file along with <code>python nsbug.py example.py</code> I only get:</p>
  
  <pre><code> &lt;CursorKind.TRANSLATION_UNIT&gt;
    "example.h"
  {
  
    (deleted lots of clang-generated definitions such as __VERSION__)
  
    Geom &lt;CursorKind.VAR_DECL&gt;
      "Geom"
  }
  </code></pre>
  
  <p>Why does is the <code>Geom</code> name space in the AST as a VAR_DECL?  I would have expected no difference, except in the preprocessor cursors.</p>
  
  <p>The work-around is obvious--just make a temp file in memory that includes the header--but that isn't very satisfying.  Can someone enlighten me?</p>