Add size/alignment/offset to C++ IR and populate. These values are not being serialized to JSON yet, so no need to change Rust code -- that will happen in a followup CL. PiperOrigin-RevId: 397309514
diff --git a/rs_bindings_from_cc/ast_visitor.cc b/rs_bindings_from_cc/ast_visitor.cc index 5c88eeb..42871e5 100644 --- a/rs_bindings_from_cc/ast_visitor.cc +++ b/rs_bindings_from_cc/ast_visitor.cc
@@ -17,6 +17,7 @@ #include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h" #include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h" #include "third_party/llvm/llvm-project/clang/include/clang/AST/Mangle.h" +#include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h" #include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h" #include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h" #include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h" @@ -97,6 +98,8 @@ default_access = clang::AS_private; } } + const clang::ASTRecordLayout& layout = + record_decl->getASTContext().getASTRecordLayout(record_decl); for (const clang::FieldDecl* field_decl : record_decl->fields()) { auto type = ConvertType(field_decl->getType(), field_decl->getASTContext()); if (!type.ok()) { @@ -107,11 +110,16 @@ if (access == clang::AS_none) { access = default_access; } - fields.push_back({.identifier = GetTranslatedName(field_decl), - .type = *type, - .access = TranslateAccessSpecifier(access)}); + fields.push_back( + {.identifier = GetTranslatedName(field_decl), + .type = *type, + .access = TranslateAccessSpecifier(access), + .offset = layout.getFieldOffset(field_decl->getFieldIndex())}); } - ir_.records.push_back({GetTranslatedName(record_decl), std::move(fields)}); + ir_.records.push_back({.identifier = GetTranslatedName(record_decl), + .fields = std::move(fields), + .size = layout.getSize().getQuantity(), + .alignment = layout.getAlignment().getQuantity()}); return true; }
diff --git a/rs_bindings_from_cc/ast_visitor_test.cc b/rs_bindings_from_cc/ast_visitor_test.cc index 23ace9d..8cc741a 100644 --- a/rs_bindings_from_cc/ast_visitor_test.cc +++ b/rs_bindings_from_cc/ast_visitor_test.cc
@@ -107,9 +107,33 @@ return testing::Field(&Record::fields, ElementsAre(matchers...)); } +// Matches a Record that has the given size. +MATCHER_P(RecordSizeIs, size, "") { + if (arg.size == size) return true; + + *result_listener << "actual size: " << arg.size; + return false; +} + +// Matches a Record that has the given alignment. +MATCHER_P(AlignmentIs, alignment, "") { + if (arg.alignment == alignment) return true; + + *result_listener << "actual alignment: " << arg.alignment; + return false; +} + // Matches a Field that has the given access specifier. MATCHER_P(AccessIs, access, "") { return arg.access == access; } +// Matches a Field that has the given offset. +MATCHER_P(OffsetIs, offset, "") { + if (arg.offset == offset) return true; + + *result_listener << "actual offset: " << arg.offset; + return false; +} + // Matches a Field with a type that matches all given matchers. template <typename... Args> auto FieldType(const Args&... matchers) { @@ -227,12 +251,13 @@ {"struct SomeStruct { int first_field; int second_field; };"}, {}); EXPECT_THAT(ir.functions, IsEmpty()); - EXPECT_THAT( - ir.records, - ElementsAre(AllOf( - IdentifierIs("SomeStruct"), - FieldsAre(AllOf(IdentifierIs("first_field"), FieldType(IsInt())), - AllOf(IdentifierIs("second_field"), FieldType(IsInt())))))); + EXPECT_THAT(ir.records, + ElementsAre(AllOf( + IdentifierIs("SomeStruct"), RecordSizeIs(8), AlignmentIs(4), + FieldsAre(AllOf(IdentifierIs("first_field"), + FieldType(IsInt()), OffsetIs(0)), + AllOf(IdentifierIs("second_field"), + FieldType(IsInt()), OffsetIs(32)))))); } TEST(AstVisitorTest, MemberVariableAccessSpecifiers) {
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h index 6fc6f24..4351839 100644 --- a/rs_bindings_from_cc/ir.h +++ b/rs_bindings_from_cc/ir.h
@@ -146,6 +146,8 @@ Identifier identifier; Type type; AccessSpecifier access; + // Field offset in bits. + uint64_t offset; }; // A record (struct, class, union). @@ -154,6 +156,9 @@ Identifier identifier; std::vector<Field> fields; + // Size and alignment in bytes. + int64_t size; + int64_t alignment; }; // A complete intermediate representation of bindings for publicly accessible