<html><head><meta http-equiv="Content-Type" content="text/html charset=iso-8859-1"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">On Mar 25, 2013, at 5:24 PM, Loïc Jaquemet <<a href="mailto:loic.jaquemet@gmail.com">loic.jaquemet@gmail.com</a>> wrote:<br><div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite"><blockquote type="cite">Does this handle anonymous structs/unions ? For example:<br><br>struct Test {<br> struct {<br>   union {<br>     int foo;<br>   };<br> };<br>};<br><br>If I pass "struct Test", "foo" will it work ? If yes, could you add a<br>related test ?<br><br></blockquote><br>It does not work.<br>I will look into that.<br></blockquote><br>And now it does handle anonymous records.<br>I added some tests cases and changed the unit test code.<br></div></blockquote><div><br></div><div><div>+  /**</div><div>+   * \brief One field in the record is an incomplete Type.</div><div>+   */</div><div>+  CXTypeLayoutError_IncompleteFieldParent = -6,</div><div>+  /**</div><div>+   * \brief One field in the record is a dependent Type.</div><div>+   */</div><div>+  CXTypeLayoutError_DependentFieldParent = -7</div><div>+};</div><div><br></div><div>This was a bit confusing until I read</div><div><br></div><div><div>+ * If in the record there is another field's type declaration that is</div><div>+ *   an incomplete type, CXTypeLayoutError_IncompleteFieldParent is returned.</div><div>+ * If in the record there is another field's type declaration that is</div><div>+ *   a dependent type, CXTypeLayoutError_DependentFieldParent is returned.</div><div>+ */</div></div><div><br></div><div>Could we change it to a simpler, "the parent record is incomplete/dependent" ?</div><div><br></div><div><br></div><div><div>+/**</div><div>+ * \brief Returns 1 if the cursor specifies a Record member that is a bitfield.</div><div>+ */</div><div>+CINDEX_LINKAGE unsigned clang_Cursor_isBitField(CXCursor C);</div></div><div><br></div><div>the convention that we use is "Returns non-zero if ..."</div><div><br></div><div><br></div><div><div>+static long long visitRecordForNamedField(const RecordDecl *RD,</div><div>+                                          StringRef FieldName) {</div><div>+  for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();</div><div>+       I != E; ++I) {</div><div>+    // handle normal fieldname, fieldname == '' == anonymous record, and</div><div>+    // field name in a anonymous record</div><div>+    if (FieldName.equals((*I)->getName())) {</div><div>+      return getOffsetOfFieldDecl((*I));</div><div>+    } else if ((*I)->isAnonymousStructOrUnion()) {</div><div>+      const RecordType *ChildType = (*I)->getType()->getAs<RecordType>();</div><div>+      if (const RecordDecl *Child = ChildType->getDecl()) {</div><div>+        long long Offset = visitRecordForNamedField(Child, FieldName);</div><div>+        if (Offset == CXTypeLayoutError_InvalidFieldName) {</div><div>+            continue;</div><div>+        } else if (Offset < 0) {</div><div>+            return Offset;</div><div>+        } else {</div><div>+            // result is relative to anonymous struct offset</div><div>+            long long ParentOffset = getOffsetOfFieldDecl((*I));</div><div>+            if (ParentOffset < 0)</div><div>+                return ParentOffset;</div><div>+            return Offset+ParentOffset;</div><div>+        }</div><div>+      } // else try next field</div><div>+    }</div><div>+  }</div><div>+  return CXTypeLayoutError_InvalidFieldName;</div><div>+}</div><div>+</div><div>+long long clang_Type_getOffsetOf(CXType PT, const char *S) {</div><div>+  // get the parent record type declaration</div><div>+  CXCursor PC = clang_getTypeDeclaration(PT);</div><div>+  if (clang_isInvalid(PC.kind))</div><div>+    return CXTypeLayoutError_Invalid;</div><div>+  const RecordDecl *RD =</div><div>+        dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC));</div><div>+  if (!RD)</div><div>+    return CXTypeLayoutError_Invalid;</div><div>+  RD = RD->getDefinition();</div><div>+  if (!RD)</div><div>+    return CXTypeLayoutError_IncompleteFieldParent;</div><div>+  QualType RT = GetQualType(PT);</div><div>+  if (RT->isIncompleteType())</div><div>+    return CXTypeLayoutError_IncompleteFieldParent;</div><div>+  if (RT->isDependentType())</div><div>+    return CXTypeLayoutError_DependentFieldParent;</div><div>+  // iterate the fields to get the matching name</div><div>+  StringRef FieldName = StringRef(S);</div><div>+  return visitRecordForNamedField(RD, FieldName);</div><div>+}</div></div><div><br></div><div>I think there is a simpler and more efficient way to handle fields in anonymous records, something like this:</div><div>Inside clang_Type_getOffsetOf():</div><div><br></div><div>  CXTranslationUnit TU =<br>      static_cast<CXTranslationUnit>(const_cast<void*>(PT.data[1]));<br>  ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext();<br>  IdentifierInfo *II = &Ctx.Idents.get(S);<br>  DeclarationName FieldName(II);<br>  RecordDecl::lookup_const_result Res = RD->lookup(FieldName);<br>  if (Res.size() != 1)<br>    return CXTypeLayoutError_InvalidFieldName;<br>  if (const FieldDecl *FD = dyn_cast<FieldDecl>(Res.front()))<br>    return getOffsetOfFieldDecl(FD);<br>  if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(Res.front()))<br>    return Ctx.getFieldOffset(IFD); // Change getOffsetOfFieldDecl() to accept IFD.<br><br>  return CXTypeLayoutError_InvalidFieldName;<br><br></div><div><br></div></div><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br>I also removed the duplicate clang_Cursor_getOffsetOf().<br>After consideration, it did not make sense, especially in the<br>anonymous record situation.<br></div></blockquote><div><br></div><div>Not sure about this, clang_Cursor_getOffsetOf is arguable more useful than clang_Type_getOffsetOf.</div><div>Let's say you have this use-case: "visit all fields in a record and get their offsets". To do this (as your changes in c-index-test show) you need to use this roundabout way where, you have the field, then you get its name, and pass it to clang_Type_getOffsetOf which looks for the same field.</div><div>Can't clang_Cursor_getOffsetOf just work, for example if you have a cursor for "foo" in</div><div><br></div><div>struct S {</div><div>   struct {</div><div>      int foo;</div><div>   };</div><div>};</div><div><br></div><div>it should just return the offset of "foo" inside "struct S".</div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br>Please see attached diffs.<br><br>* Implementation of sizeof, alignof and offsetof for libclang.<br>* Unit Tests<br>* Python bindings<br>* Python tests<br><br><br><br><br><br>--<span class="Apple-converted-space"> </span><br>Loïc Jaquemet<br><span><sizeof-alignof-offsetof-001></span><span><sizeof-alignof-offsetof-002-tests></span><span><sizeof-alignof-offsetof-003-python-bindings></span><span><sizeof-alignof-offsetof-004-python-bindings-tests></span></div></blockquote></div><br></body></html>