Skip to content

Handle opaque types #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions bindgen/TypeTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ TypeTranslator::TypeTranslator(clang::ASTContext *ctx_, IR &ir)
typeMap["char32_t"] = "native.CChar32";
typeMap["float"] = "native.CFloat";
typeMap["double"] = "native.CDouble";
typeMap["long double"] = "native.CDouble";
}

std::shared_ptr<Type>
Expand Down Expand Up @@ -86,15 +87,23 @@ TypeTranslator::translatePointer(const clang::QualType &pte,
std::shared_ptr<Type>
TypeTranslator::translateStructOrUnionOrEnum(const clang::QualType &qtpe) {
std::string name = qtpe.getUnqualifiedType().getAsString();
std::string nameWithoutSpace = replaceChar(name, " ", "_");

auto it = aliasesMap.find(name);
if (it != aliasesMap.end()) {
/* name contains space: struct <name>.
* Use type alias instead struct type */
return (*it).second;
/* If the struct was already declared then there is a TypeDef instance
* with appropriate name.
*
* If there is no such TypeDef then the type is opaque and TypeDef with
* nullptr will be generated for the type. */

std::shared_ptr<TypeDef> typeDef = ir.getTypeDefWithName(nameWithoutSpace);
if (typeDef) {
return typeDef;
}
/* type has typedef alias */
return ir.getTypeDefWithName(name);
/* type is not yet defined.
* TypeDef with nullptr will be created.
* nullptr will be replaced by actual type when the type is declared. */
typeDef = ir.addTypeDef(nameWithoutSpace, nullptr);
return typeDef;
}

std::shared_ptr<Type>
Expand Down Expand Up @@ -138,6 +147,10 @@ std::shared_ptr<Type> TypeTranslator::translate(const clang::QualType &qtpe,
std::make_shared<PrimitiveType>("Byte"), sizeInBits / 8);
}

if (tpe->isFunctionType()) {
return nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for static inline functions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it always used to return nullptr for function type, I just made it explicit.

I found this declaration in libio.h:

typedef __ssize_t __io_read_fn (void *__cookie, char *__buf, size_t __nbytes);

That caused an error because TypeDef was created with nullptr.

Actually I am not aware of where function types may be used and what should we do with them. Maybe we should create an issue for investigating it.

}

if (tpe->isFunctionPointerType()) {
return translateFunctionPointer(qtpe, avoid);

Expand Down Expand Up @@ -171,10 +184,6 @@ std::shared_ptr<Type> TypeTranslator::translate(const clang::QualType &qtpe,
}
}

void TypeTranslator::addAlias(std::string cName, std::shared_ptr<Type> type) {
aliasesMap[cName] = type;
}

std::string TypeTranslator::getTypeFromTypeMap(std::string cType) {
auto it = typeMap.find(cType);
if (it != typeMap.end()) {
Expand Down
9 changes: 1 addition & 8 deletions bindgen/TypeTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ class TypeTranslator {
* @param tpe The type to translate
* @param avoid A type to avoid, useful to avoid cyclic definitions inside
* structs, unions, ...
* @return the type translated
* @return the type translated or nullptr if type is function type.
*/
std::shared_ptr<Type> translate(const clang::QualType &tpe,
const std::string * = nullptr);

void addAlias(std::string cName, std::shared_ptr<Type> type);

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

private:
Expand All @@ -30,11 +28,6 @@ class TypeTranslator {
*/
std::map<std::string, std::string> typeMap;

/**
* Maps C struct, union or enum name to Type alias
*/
std::map<std::string, std::shared_ptr<Type>> aliasesMap;

std::shared_ptr<Type>
translateStructOrUnionOrEnum(const clang::QualType &qtpe);

Expand Down
10 changes: 10 additions & 0 deletions bindgen/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ template <typename T, typename PT> static inline bool isInstanceOf(PT *type) {
return p != nullptr;
}

static inline std::string replaceChar(const std::string &str,
const std::string &c1,
const std::string &c2) {
auto f = str.find(c1);
if (f != std::string::npos) {
return std::string(str).replace(f, c1.length(), c2);
}
return std::string(str);
}

/**
* Types may be wrapper in a chain of typedefs.
* @return true if given type is of type T or is an alias for type T.
Expand Down
2 changes: 1 addition & 1 deletion bindgen/ir/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Parameter::Parameter(std::string name, std::shared_ptr<Type> type)
Function::Function(const std::string &name, std::vector<Parameter *> parameters,
std::shared_ptr<Type> retType, bool isVariadic)
: name(name), scalaName(name), parameters(std::move(parameters)),
retType(retType), isVariadic(isVariadic) {}
retType(std::move(retType)), isVariadic(isVariadic) {}

llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) {
if (func.scalaName != func.name) {
Expand Down
43 changes: 29 additions & 14 deletions bindgen/ir/IR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ void IR::addFunction(std::string name, std::vector<Parameter *> parameters,
retType, isVariadic));
}

void IR::addTypeDef(std::string name, std::shared_ptr<Type> type) {
std::shared_ptr<TypeDef> IR::addTypeDef(std::string name,
std::shared_ptr<Type> type) {
typeDefs.push_back(std::make_shared<TypeDef>(std::move(name), type));
return typeDefs.back();
}

std::shared_ptr<Type> IR::addEnum(std::string name, const std::string &type,
Expand All @@ -28,23 +30,32 @@ std::shared_ptr<Type> IR::addEnum(std::string name, const std::string &type,
return nullptr;
}

std::shared_ptr<Type> IR::addStruct(std::string name,
std::vector<Field *> fields,
uint64_t typeSize) {
void IR::addStruct(std::string name, std::vector<Field *> fields,
uint64_t typeSize) {
std::shared_ptr<Struct> s =
std::make_shared<Struct>(std::move(name), std::move(fields), typeSize);
std::make_shared<Struct>(name, std::move(fields), typeSize);
structs.push_back(s);
typeDefs.push_back(s->generateTypeDef());
return typeDefs.back();
std::shared_ptr<TypeDef> typeDef = getTypeDefWithName("struct_" + name);
if (typeDef) {
/* the struct type used to be opaque type, typeDef contains nullptr */
typeDef.get()->setType(s);
} else {
typeDefs.push_back(s->generateTypeDef());
}
}

std::shared_ptr<Type>
IR::addUnion(std::string name, std::vector<Field *> fields, uint64_t maxSize) {
void IR::addUnion(std::string name, std::vector<Field *> fields,
uint64_t maxSize) {
std::shared_ptr<Union> u =
std::make_shared<Union>(std::move(name), std::move(fields), maxSize);
std::make_shared<Union>(name, std::move(fields), maxSize);
unions.push_back(u);
typeDefs.push_back(u->generateTypeDef());
return typeDefs.back();
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);
} else {
typeDefs.push_back(u->generateTypeDef());
}
}

void IR::addLiteralDefine(std::string name, std::string literal,
Expand Down Expand Up @@ -304,6 +315,11 @@ std::shared_ptr<Variable> IR::addVariable(const std::string &name,
}

std::shared_ptr<TypeDef> IR::getTypeDefWithName(const std::string &name) {
/* nullptr is returned in 2 cases:
* 1. TypeTranslator translates opaque struct/union type for which TypeDef
* was not created.
* 2. TreeVisitor visits struct/union declaration and it checks whether a
* TypeDef already exists for it.*/
return getDeclarationWithName(typeDefs, name);
}

Expand All @@ -317,7 +333,6 @@ T IR::getDeclarationWithName(std::vector<T> &declarations,
return declaration;
}
}
llvm::errs() << "Failed to get declaration for " << name << "\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we throw an exception here to avoid segfaults.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, nullptr is returned when:

  1. struct or union type is needed by a function (or other declaration) but the type is not declared yet. So TypeDef with nullptr will be created.
  2. When TreeVisitor visits struct/union declaration we need to check whether a TypeDef already exists for it.

I'll add comments about this to the code.

return nullptr;
}

Expand All @@ -331,4 +346,4 @@ IR::~IR() {
possibleVarDefines.clear();
variables.clear();
varDefines.clear();
}
}
19 changes: 6 additions & 13 deletions bindgen/ir/IR.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,20 @@ class IR {
void addFunction(std::string name, std::vector<Parameter *> parameters,
std::shared_ptr<Type> retType, bool isVariadic);

void addTypeDef(std::string name, std::shared_ptr<Type> type);
std::shared_ptr<TypeDef> addTypeDef(std::string name,
std::shared_ptr<Type> type);

/**
* @return type alias for the enum
*/
std::shared_ptr<Type> addEnum(std::string name, const std::string &type,
std::vector<Enumerator> enumerators);

/**
* @return type alias for the struct
*/
std::shared_ptr<Type>
addStruct(std::string name, std::vector<Field *> fields, uint64_t typeSize);
void addStruct(std::string name, std::vector<Field *> fields,
uint64_t typeSize);

/**
* @return type alias for the union
*/
std::shared_ptr<Type>
addUnion(std::string name, std::vector<Field *> fields, uint64_t maxSize);
void addUnion(std::string name, std::vector<Field *> fields,
uint64_t maxSize);

void addLiteralDefine(std::string name, std::string literal,
std::shared_ptr<Type> type);
Expand Down Expand Up @@ -138,8 +133,6 @@ class IR {
T getDeclarationWithName(std::vector<T> &declarations,
const std::string &name);

template <typename T> void clearVector(std::vector<T> v);

std::string libName; // name of the library
std::string linkName; // name of the library to link with
std::string objectName; // name of Scala object
Expand Down
1 change: 0 additions & 1 deletion bindgen/ir/Struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "types/ArrayType.h"
#include "types/PrimitiveType.h"
#include <sstream>
#include <utility>

Field::Field(std::string name, std::shared_ptr<Type> type)
: TypeAndName(std::move(name), std::move(type)) {}
Expand Down
2 changes: 1 addition & 1 deletion bindgen/ir/TypeAndName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <clang/Tooling/Tooling.h>

TypeAndName::TypeAndName(std::string name, std::shared_ptr<Type> type)
: name(std::move(name)), type(type) {}
: name(std::move(name)), type(std::move(type)) {}

std::shared_ptr<Type> TypeAndName::getType() const { return type; }

Expand Down
8 changes: 7 additions & 1 deletion bindgen/ir/TypeDef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
#include "../Utils.h"

TypeDef::TypeDef(std::string name, std::shared_ptr<Type> type)
: TypeAndName(std::move(name), type) {}
: TypeAndName(std::move(name), std::move(type)) {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is std:: move needed here? My understanding is that ownership does not have to be explicitly transferred or is this an optimization?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just a small optimization.


llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const TypeDef &typeDef) {
if (!typeDef.getType()) {
llvm::errs() << "Error: type declaration for " << typeDef.getName()
<< " was not found.\n";
llvm::errs().flush();
return s;
}
s << " type " + handleReservedWords(typeDef.name) + " = " +
typeDef.getType()->str() + "\n";
return s;
Expand Down
4 changes: 1 addition & 3 deletions bindgen/ir/types/ArrayType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include "../../Utils.h"

ArrayType::ArrayType(std::shared_ptr<Type> elementsType, uint64_t size)
: size(size), elementsType(elementsType) {}
: size(size), elementsType(std::move(elementsType)) {}

std::string ArrayType::str() const {
return "native.CArray[" + elementsType->str() + ", " +
Expand All @@ -12,5 +12,3 @@ std::string ArrayType::str() const {
bool ArrayType::usesType(std::shared_ptr<Type> type) const {
return this == type.get() || elementsType == type;
}

ArrayType::~ArrayType() {}
2 changes: 1 addition & 1 deletion bindgen/ir/types/ArrayType.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ArrayType : public Type {
public:
ArrayType(std::shared_ptr<Type> elementsType, uint64_t size);

~ArrayType() override;
~ArrayType() override = default;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL


bool usesType(std::shared_ptr<Type> type) const override;

Expand Down
6 changes: 2 additions & 4 deletions bindgen/ir/types/FunctionPointerType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
FunctionPointerType::FunctionPointerType(
std::shared_ptr<Type> returnType,
const std::vector<std::shared_ptr<Type>> &parametersTypes, bool isVariadic)
: returnType(returnType), parametersTypes(parametersTypes),
: returnType(std::move(returnType)), parametersTypes(parametersTypes),
isVariadic(isVariadic) {}

std::string FunctionPointerType::str() const {
Expand All @@ -30,12 +30,10 @@ bool FunctionPointerType::usesType(std::shared_ptr<Type> type) const {
return true;
}

for (auto parameterType : parametersTypes) {
for (const auto &parameterType : parametersTypes) {
if (parameterType == type) {
return true;
}
}
return false;
}

FunctionPointerType::~FunctionPointerType() {}
2 changes: 1 addition & 1 deletion bindgen/ir/types/FunctionPointerType.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class FunctionPointerType : public Type {
const std::vector<std::shared_ptr<Type>> &parametersTypes,
bool isVariadic);

~FunctionPointerType() override;
~FunctionPointerType() override = default;

bool usesType(std::shared_ptr<Type> type) const override;

Expand Down
4 changes: 1 addition & 3 deletions bindgen/ir/types/PointerType.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "PointerType.h"

PointerType::PointerType(std::shared_ptr<Type> type) : type(type) {}
PointerType::PointerType(std::shared_ptr<Type> type) : type(std::move(type)) {}

std::string PointerType::str() const {
return "native.Ptr[" + type->str() + "]";
Expand All @@ -12,5 +12,3 @@ bool PointerType::usesType(std::shared_ptr<Type> type) const {
}
return this->type == type;
}

PointerType::~PointerType() {}
2 changes: 1 addition & 1 deletion bindgen/ir/types/PointerType.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class PointerType : public Type {
public:
explicit PointerType(std::shared_ptr<Type> type);

~PointerType() override;
~PointerType() override = default;

bool usesType(std::shared_ptr<Type> type) const override;

Expand Down
2 changes: 0 additions & 2 deletions bindgen/ir/types/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,3 @@
std::string Type::str() const { return ""; }

bool Type::usesType(std::shared_ptr<Type> type) const { return false; }

Type::~Type() = default;
2 changes: 1 addition & 1 deletion bindgen/ir/types/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/
class Type {
public:
virtual ~Type();
virtual ~Type() = default;

virtual std::string str() const;

Expand Down
Loading