Skip to content

Commit

Permalink
Merge pull request #134 from kornilova-l/anonymous-types
Browse files Browse the repository at this point in the history
Generate type for anonymous structs, unions and inner enums
  • Loading branch information
kornilova203 authored Jul 28, 2018
2 parents 4bc278e + 8c96f21 commit 607f4fc
Show file tree
Hide file tree
Showing 12 changed files with 235 additions and 111 deletions.
109 changes: 97 additions & 12 deletions bindgen/TypeTranslator.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "TypeTranslator.h"
#include "Utils.h"
#include "ir/types/FunctionPointerType.h"
#include "ir/types/PointerType.h"
#include "clang/AST/RecordLayout.h"

TypeTranslator::TypeTranslator(clang::ASTContext *ctx_, IR &ir)
: ctx(ctx_), ir(ir), typeMap() {
Expand Down Expand Up @@ -106,13 +106,19 @@ TypeTranslator::translateStructOrUnionOrEnum(const clang::QualType &qtpe) {
std::shared_ptr<Type>
TypeTranslator::translateStructOrUnion(const clang::QualType &qtpe) {
if (qtpe->hasUnnamedOrLocalType()) {
// TODO: Verify that the local part is not a problem
uint64_t sizeInBits = ctx->getTypeSize(qtpe);
assert(sizeInBits % 8 == 0);
return std::make_shared<ArrayType>(
std::make_shared<PrimitiveType>("Byte"), sizeInBits / 8);
if (qtpe->isStructureType()) {
std::string name =
"anonymous_" + std::to_string(anonymousStructId++);
clang::RecordDecl *record = qtpe->getAsStructureType()->getDecl();
return addStructDefinition(record, name);
} else if (qtpe->isUnionType()) {
std::string name =
"anonymous_" + std::to_string(anonymousUnionId++);
clang::RecordDecl *record = qtpe->getAsUnionType()->getDecl();
return addUnionDefinition(record, name);
}
return nullptr;
}

return translateStructOrUnionOrEnum(qtpe);
}

Expand Down Expand Up @@ -144,14 +150,11 @@ std::shared_ptr<Type> TypeTranslator::translate(const clang::QualType &qtpe) {
return translatePointer(
tpe->getAs<clang::PointerType>()->getPointeeType());

} else if (qtpe->isStructureType()) {
return translateStructOrUnion(qtpe);

} else if (qtpe->isUnionType()) {
} else if (qtpe->isStructureType() || qtpe->isUnionType()) {
return translateStructOrUnion(qtpe);

} else if (qtpe->isEnumeralType()) {
return translateStructOrUnionOrEnum(qtpe);
return translateEnum(qtpe);

} else if (qtpe->isConstantArrayType()) {
return translateConstantArray(ctx->getAsConstantArrayType(qtpe));
Expand All @@ -176,3 +179,85 @@ std::string TypeTranslator::getTypeFromTypeMap(std::string cType) {
}
return "";
}

std::shared_ptr<Location> TypeTranslator::getLocation(clang::Decl *decl) {
clang::SourceManager &sm = ctx->getSourceManager();
std::string filename = std::string(sm.getFilename(decl->getLocation()));
char *p = realpath(filename.c_str(), nullptr);
std::string path;
if (p) {
path = p;
delete[] p;
} else {
// TODO: check when it happens
path = "";
}

unsigned lineNumber = sm.getSpellingLineNumber(decl->getLocation());
return std::make_shared<Location>(path, lineNumber);
}

std::shared_ptr<TypeDef>
TypeTranslator::addUnionDefinition(clang::RecordDecl *record,
std::string name) {
std::vector<std::shared_ptr<Field>> fields;

for (const clang::FieldDecl *field : record->fields()) {
std::string fname = field->getNameAsString();
std::shared_ptr<Type> ftype = translate(field->getType());

fields.push_back(std::make_shared<Field>(fname, ftype));
}

uint64_t sizeInBits = ctx->getTypeSize(record->getTypeForDecl());
assert(sizeInBits % 8 == 0);

return ir.addUnion(name, std::move(fields), sizeInBits / 8,
getLocation(record));
}

std::shared_ptr<TypeDef>
TypeTranslator::addStructDefinition(clang::RecordDecl *record,
std::string name) {
std::string newName = "struct_" + name;

if (record->hasAttr<clang::PackedAttr>()) {
llvm::errs() << "Warning: struct " << name << " is packed. "
<< "Packed structs are not supported by Scala Native. "
<< "Access to fields will not work correctly.\n";
llvm::errs().flush();
}

std::vector<std::shared_ptr<Field>> fields;
const clang::ASTRecordLayout &recordLayout =
ctx->getASTRecordLayout(record);

bool isBitFieldStruct = false;
for (const clang::FieldDecl *field : record->fields()) {
if (field->isBitField()) {
isBitFieldStruct = true;
}
std::shared_ptr<Type> ftype = translate(field->getType());
uint64_t recordOffsetInBits =
recordLayout.getFieldOffset(field->getFieldIndex());
fields.push_back(std::make_shared<Field>(field->getNameAsString(),
ftype, recordOffsetInBits));
}

uint64_t sizeInBits = ctx->getTypeSize(record->getTypeForDecl());
assert(sizeInBits % 8 == 0);

return ir.addStruct(name, std::move(fields), sizeInBits / 8,
getLocation(record),
record->hasAttr<clang::PackedAttr>(), isBitFieldStruct);
}

std::shared_ptr<Type>
TypeTranslator::translateEnum(const clang::QualType &type) {
if (type->hasUnnamedOrLocalType()) {
clang::EnumDecl *enumDecl = type->getAs<clang::EnumType>()->getDecl();
return std::make_shared<PrimitiveType>(getTypeFromTypeMap(
enumDecl->getIntegerType().getUnqualifiedType().getAsString()));
}
return translateStructOrUnionOrEnum(type);
}
12 changes: 12 additions & 0 deletions bindgen/TypeTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,19 @@ class TypeTranslator {

std::string getTypeFromTypeMap(std::string cType);

std::shared_ptr<TypeDef> addUnionDefinition(clang::RecordDecl *record,
std::string name);

std::shared_ptr<TypeDef> addStructDefinition(clang::RecordDecl *record,
std::string name);

std::shared_ptr<Location> getLocation(clang::Decl *decl);

private:
clang::ASTContext *ctx;
IR &ir;
int anonymousStructId = 0;
int anonymousUnionId = 0;

/**
* Primitive types
Expand All @@ -36,4 +46,6 @@ class TypeTranslator {

std::shared_ptr<Type>
translateConstantArray(const clang::ConstantArrayType *ar);

std::shared_ptr<Type> translateEnum(const clang::QualType &type);
};
16 changes: 11 additions & 5 deletions bindgen/ir/IR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ void IR::addEnum(std::string name, const std::string &type,
}
}

void IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t typeSize, std::shared_ptr<Location> location,
bool isPacked, bool isBitField) {
std::shared_ptr<TypeDef>
IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t typeSize, std::shared_ptr<Location> location,
bool isPacked, bool isBitField) {
std::shared_ptr<Struct> s =
std::make_shared<Struct>(name, std::move(fields), typeSize,
std::move(location), isPacked, isBitField);
Expand All @@ -44,22 +45,27 @@ void IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
if (typeDef) {
/* the struct type used to be opaque type, typeDef contains nullptr */
typeDef.get()->setType(s);
return typeDef;
} else {
typeDefs.push_back(s->generateTypeDef());
return typeDefs.back();
}
}

void IR::addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t maxSize, std::shared_ptr<Location> location) {
std::shared_ptr<TypeDef>
IR::addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t maxSize, std::shared_ptr<Location> location) {
std::shared_ptr<Union> u = std::make_shared<Union>(
name, std::move(fields), maxSize, std::move(location));
unions.push_back(u);
std::shared_ptr<TypeDef> typeDef = getTypeDefWithName("union_" + name);
if (typeDef) {
/* the union type used to be opaque type, typeDef contains nullptr */
typeDef.get()->setType(u);
return typeDef;
} else {
typeDefs.push_back(u->generateTypeDef());
return typeDefs.back();
}
}

Expand Down
14 changes: 8 additions & 6 deletions bindgen/ir/IR.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ class IR {
std::vector<Enumerator> enumerators,
std::shared_ptr<Location> location);

void addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t typeSize, std::shared_ptr<Location> location,
bool isPacked, bool isBitField);

void addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t maxSize, std::shared_ptr<Location> location);
std::shared_ptr<TypeDef>
addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t typeSize, std::shared_ptr<Location> location,
bool isPacked, bool isBitField);

std::shared_ptr<TypeDef>
addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
uint64_t maxSize, std::shared_ptr<Location> location);

void addLiteralDefine(std::string name, std::string literal,
std::shared_ptr<Type> type);
Expand Down
78 changes: 5 additions & 73 deletions bindgen/visitor/TreeVisitor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "TreeVisitor.h"
#include "clang/AST/RecordLayout.h"

bool TreeVisitor::VisitFunctionDecl(clang::FunctionDecl *func) {
if (!astContext->getSourceManager().isInMainFile(func->getLocation())) {
Expand Down Expand Up @@ -37,7 +36,7 @@ bool TreeVisitor::VisitTypedefDecl(clang::TypedefDecl *tpdef) {
std::shared_ptr<Type> type =
typeTranslator.translate(tpdef->getUnderlyingType());
if (type) {
ir.addTypeDef(name, type, getLocation(tpdef));
ir.addTypeDef(name, type, typeTranslator.getLocation(tpdef));
}
return true;
}
Expand All @@ -59,7 +58,8 @@ bool TreeVisitor::VisitEnumDecl(clang::EnumDecl *enumdecl) {
std::string scalaType = typeTranslator.getTypeFromTypeMap(
enumdecl->getIntegerType().getUnqualifiedType().getAsString());

ir.addEnum(name, scalaType, std::move(enumerators), getLocation(enumdecl));
ir.addEnum(name, scalaType, std::move(enumerators),
typeTranslator.getLocation(enumdecl));

return true;
}
Expand All @@ -76,68 +76,17 @@ bool TreeVisitor::VisitRecordDecl(clang::RecordDecl *record) {

if (record->isUnion() && record->isThisDeclarationADefinition() &&
!record->isAnonymousStructOrUnion() && !name.empty()) {
handleUnion(record, name);
typeTranslator.addUnionDefinition(record, name);
return true;

} else if (record->isStruct() && record->isThisDeclarationADefinition() &&
!record->isAnonymousStructOrUnion() && !name.empty()) {
handleStruct(record, name);
typeTranslator.addStructDefinition(record, name);
return true;
}
return false;
}

void TreeVisitor::handleUnion(clang::RecordDecl *record, std::string name) {
std::vector<std::shared_ptr<Field>> fields;

for (const clang::FieldDecl *field : record->fields()) {
std::string fname = field->getNameAsString();
std::shared_ptr<Type> ftype =
typeTranslator.translate(field->getType());

fields.push_back(std::make_shared<Field>(fname, ftype));
}

uint64_t sizeInBits = astContext->getTypeSize(record->getTypeForDecl());
assert(sizeInBits % 8 == 0);

ir.addUnion(name, std::move(fields), sizeInBits / 8, getLocation(record));
}

void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) {
std::string newName = "struct_" + name;

if (record->hasAttr<clang::PackedAttr>()) {
llvm::errs() << "Warning: struct " << name << " is packed. "
<< "Packed structs are not supported by Scala Native. "
<< "Access to fields will not work correctly.\n";
llvm::errs().flush();
}

std::vector<std::shared_ptr<Field>> fields;
const clang::ASTRecordLayout &recordLayout =
astContext->getASTRecordLayout(record);

bool isBitFieldStruct = false;
for (const clang::FieldDecl *field : record->fields()) {
if (field->isBitField()) {
isBitFieldStruct = true;
}
std::shared_ptr<Type> ftype =
typeTranslator.translate(field->getType());
uint64_t recordOffsetInBits =
recordLayout.getFieldOffset(field->getFieldIndex());
fields.push_back(std::make_shared<Field>(field->getNameAsString(),
ftype, recordOffsetInBits));
}

uint64_t sizeInBits = astContext->getTypeSize(record->getTypeForDecl());
assert(sizeInBits % 8 == 0);

ir.addStruct(name, std::move(fields), sizeInBits / 8, getLocation(record),
record->hasAttr<clang::PackedAttr>(), isBitFieldStruct);
}

bool TreeVisitor::VisitVarDecl(clang::VarDecl *varDecl) {
if (!astContext->getSourceManager().isInMainFile(varDecl->getLocation())) {
/* include variables only from the original header */
Expand All @@ -157,20 +106,3 @@ bool TreeVisitor::VisitVarDecl(clang::VarDecl *varDecl) {
}
return true;
}

std::shared_ptr<Location> TreeVisitor::getLocation(clang::Decl *decl) {
clang::SourceManager &sm = astContext->getSourceManager();
std::string filename = std::string(sm.getFilename(decl->getLocation()));
char *p = realpath(filename.c_str(), nullptr);
std::string path;
if (p) {
path = p;
delete[] p;
} else {
// TODO: check when it happens
path = "";
}

unsigned lineNumber = sm.getSpellingLineNumber(decl->getLocation());
return std::make_shared<Location>(path, lineNumber);
}
6 changes: 0 additions & 6 deletions bindgen/visitor/TreeVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ class TreeVisitor : public clang::RecursiveASTVisitor<TreeVisitor> {
TypeTranslator typeTranslator;
IR &ir;

void handleUnion(clang::RecordDecl *record, std::string name);

void handleStruct(clang::RecordDecl *record, std::string name);

std::shared_ptr<Location> getLocation(clang::Decl *decl);

public:
TreeVisitor(clang::CompilerInstance *CI, IR &ir)
: astContext(&(CI->getASTContext())), typeTranslator(astContext, ir),
Expand Down
17 changes: 17 additions & 0 deletions tests/samples/AnonymousTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* structs */

void foo(struct { char a; } * s);

struct StructWithAnonymousStruct {
struct {
union {
long a;
} * innerUnion;
} * innerStruct;

enum { A, B, C } innerEnum;
};

struct {
int result;
} * bar();
Loading

0 comments on commit 607f4fc

Please sign in to comment.