Skip to content

Commit

Permalink
Add tests. Search for type usages recursively
Browse files Browse the repository at this point in the history
  • Loading branch information
kornilova203 committed Jul 10, 2018
1 parent 902fa75 commit 5447079
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 70 deletions.
119 changes: 66 additions & 53 deletions bindgen/ir/IR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ void IR::addVarDefine(std::string name, std::shared_ptr<Variable> variable) {
}

bool IR::libObjEmpty() const {
return functions.empty() && !hasOutputtedTypeDefs() &&
return functions.empty() && !hasOutputtedDeclaration(typeDefs) &&
!hasOutputtedDeclaration(structs) &&
!hasOutputtedDeclaration(unions) && varDefines.empty() &&
variables.empty();
Expand All @@ -91,7 +91,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
s << "package " << ir.packageName << "\n\n";
}

if (!ir.libObjEmpty() || ir.hasOutputtedEnums() ||
if (!ir.libObjEmpty() || ir.hasOutputtedDeclaration(ir.enums) ||
!ir.literalDefines.empty()) {
s << "import scala.scalanative._\n"
<< "import scala.scalanative.native._\n\n";
Expand All @@ -108,7 +108,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
<< "object " << objectName << " {\n";

for (const auto &typeDef : ir.typeDefs) {
if (ir.typeDefInMainFile(*typeDef) || ir.isTypeUsed(typeDef)) {
if (ir.isOutputted(typeDef)) {
s << *typeDef;
}
}
Expand Down Expand Up @@ -136,18 +136,16 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
s << "}\n\n";
}

if (ir.hasOutputtedEnums() || ir.hasHelperMethods()) {
if (ir.hasOutputtedDeclaration(ir.enums) || ir.hasHelperMethods()) {
s << "import " << objectName << "._\n\n";
}

if (ir.hasOutputtedEnums()) {
if (ir.hasOutputtedDeclaration(ir.enums)) {
s << "object " << ir.libName << "Enums {\n";

std::string sep = "";
for (const auto &e : ir.enums) {
if (ir.inMainFile(*e) ||
(!e->isAnonymous() &&
ir.isTypeUsed(ir.getTypeDefWithName(e->getTypeAlias())))) {
if (ir.isOutputted(e)) {
s << sep << *e;
sep = "\n";
}
Expand All @@ -160,13 +158,13 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
s << "object " << ir.libName << "Helpers {\n";

for (const auto &st : ir.structs) {
if (ir.isOutputted(st.get()) && st->hasHelperMethods()) {
if (ir.isOutputted(st) && st->hasHelperMethods()) {
s << "\n" << st->generateHelperClass();
}
}

for (const auto &u : ir.unions) {
if (ir.isOutputted(u.get())) {
if (ir.isOutputted(u)) {
s << "\n" << u->generateHelperClass();
}
}
Expand All @@ -193,7 +191,7 @@ bool IR::hasHelperMethods() const {
}

for (const auto &s : structs) {
if (isOutputted(s.get()) && s->hasHelperMethods()) {
if (isOutputted(s) && s->hasHelperMethods()) {
return true;
}
}
Expand Down Expand Up @@ -259,9 +257,46 @@ bool IR::typeIsUsedOnlyInTypeDefs(const std::shared_ptr<Type> &type) const {
isTypeUsed(literalDefines, type, true));
}

bool IR::isTypeUsed(const std::shared_ptr<Type> &type) const {
return !(typeIsUsedOnlyInTypeDefs(type) &&
!isTypeUsed(typeDefs, type, false));
bool IR::isTypeUsed(const std::shared_ptr<Type> &type,
bool checkRecursively) const {
if (checkRecursively) {
if (isTypeUsed(functions, type, true) ||
isTypeUsed(variables, type, true) ||
isTypeUsed(literalDefines, type, true)) {
return true;
}
/* type is used if there exists another type that is used and that
* references this type */
for (const auto &typeDef : typeDefs) {
if (typeDef->usesType(type, false)) {
if (isOutputted(typeDef)) {
return true;
}
}
}
for (const auto &s : structs) {
/* stopOnTypeDefs parameter is true because because typedefs were
* checked */
if (s->usesType(type, true)) {
if (isOutputted(s)) {
return true;
}
}
}
for (const auto &u : unions) {
/* stopOnTypeDefs parameter is true because because typedefs were
* checked */
if (u->usesType(type, true)) {
if (isOutputted(u)) {
return true;
}
}
}
return false;
} else {
return !(typeIsUsedOnlyInTypeDefs(type) &&
!isTypeUsed(typeDefs, type, false));
}
}

void IR::setScalaNames() {
Expand Down Expand Up @@ -370,60 +405,38 @@ IR::~IR() {
varDefines.clear();
}

bool IR::typeDefInMainFile(const TypeDef &typeDef) const {
if (inMainFile(typeDef)) {
return true;
}
Type *type = typeDef.getType().get();
if (isInstanceOf<Struct>(type)) {
return inMainFile(*dynamic_cast<Struct *>(type));
}
if (isInstanceOf<Union>(type)) {
return inMainFile(*dynamic_cast<Union *>(type));
}
if (isInstanceOf<Enum>(type)) {
return inMainFile(*dynamic_cast<Enum *>(type));
}
return false;
}

template <typename T> bool IR::inMainFile(const T &type) const {
std::shared_ptr<Location> location = type.getLocation();
return location && locationManager.inMainFile(*location);
}

bool IR::hasOutputtedEnums() const {
for (const auto &e : enums) {
if (inMainFile(*e) ||
(!e->isAnonymous() &&
isTypeUsed(getTypeDefWithName(e->getTypeAlias())))) {
return true;
if (!location) {
/* generated TypeDef */
auto *typeDef = dynamic_cast<const TypeDef *>(&type);
assert(typeDef);
Type *innerType = typeDef->getType().get();
if (isInstanceOf<Struct>(innerType)) {
return inMainFile(*dynamic_cast<Struct *>(innerType));
}
}
return false;
}

bool IR::hasOutputtedTypeDefs() const {
for (const auto &typeDef : typeDefs) {
if (inMainFile(*typeDef) || isTypeUsed(typeDef)) {
return true;
if (isInstanceOf<Union>(innerType)) {
return inMainFile(*dynamic_cast<Union *>(innerType));
}
if (isInstanceOf<Enum>(innerType)) {
return inMainFile(*dynamic_cast<Enum *>(innerType));
}
}
return false;
return location && locationManager.inMainFile(*location);
}

template <typename T>
bool IR::hasOutputtedDeclaration(
const std::vector<std::shared_ptr<T>> &declarations) const {
for (const auto &declaration : declarations) {
if (isOutputted(declaration.get())) {
if (isOutputted(declaration)) {
return true;
}
}
return false;
}

bool IR::isOutputted(const StructOrUnion *structOrUnion) const {
return inMainFile(*structOrUnion) ||
isTypeUsed(getTypeDefWithName(structOrUnion->getTypeAlias()));
template <typename T>
bool IR::isOutputted(const std::shared_ptr<T> &type) const {
return inMainFile(*type) || isTypeUsed(type, true);
}
19 changes: 11 additions & 8 deletions bindgen/ir/IR.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,12 @@ class IR {
bool typeIsUsedOnlyInTypeDefs(const std::shared_ptr<Type> &type) const;

/**
* @param checkRecursively if this parameter is true then the method will
* output false if the type is used only in unused types
* @return true if type is used in one of declarations
*/
bool isTypeUsed(const std::shared_ptr<Type> &type) const;
bool isTypeUsed(const std::shared_ptr<Type> &type,
bool checkRecursively = false) const;

/**
* @return true if type is used in one of given declarations.
Expand All @@ -141,15 +144,15 @@ class IR {
T getDeclarationWithName(const std::vector<T> &declarations,
const std::string &name) const;

bool typeDefInMainFile(const TypeDef &typeDef) const;

template <typename T> bool inMainFile(const T &type) const;

bool hasOutputtedEnums() const;

bool hasOutputtedTypeDefs() const;

bool isOutputted(const StructOrUnion *structOrUnion) const;
/**
* @tparam T Type subclass
* @return true if type is in main file or it is used by declaration from
* main file.
*/
template <typename T>
bool isOutputted(const std::shared_ptr<T> &type) const;

/**
* @tparam T Struct or Union
Expand Down
2 changes: 2 additions & 0 deletions bindgen/ir/Location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ Location::Location(std::string path, int lineNumber)
: path(std::move(path)), lineNumber(lineNumber) {}

std::string Location::getPath() const { return path; }

int Location::getLineNumber() const { return lineNumber; }
2 changes: 2 additions & 0 deletions bindgen/ir/Location.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Location {

std::string getPath() const;

int getLineNumber() const;

private:
std::string path;
int lineNumber;
Expand Down
20 changes: 18 additions & 2 deletions bindgen/ir/Struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ StructOrUnion::~StructOrUnion() {
}
}

bool StructOrUnion::operator==(const StructOrUnion &other) const {
bool StructOrUnion::equals(const StructOrUnion &other) const {
if (this == &other) {
return true;
}
Expand Down Expand Up @@ -94,7 +94,7 @@ std::shared_ptr<TypeDef> Struct::generateTypeDef() {
getTypeAlias(),
std::make_shared<ArrayType>(std::make_shared<PrimitiveType>("Byte"),
typeSize),
std::move(location));
location);
}
}

Expand Down Expand Up @@ -155,6 +155,14 @@ bool Struct::usesType(const std::shared_ptr<Type> &type,
return false;
}

bool Struct::operator==(const Type &other) const {
auto *structOrUnion = dynamic_cast<const StructOrUnion *>(&other);
if (structOrUnion) {
return this->equals(*structOrUnion);
}
return false;
}

Union::Union(std::string name, std::vector<Field *> fields, uint64_t maxSize,
std::shared_ptr<Location> location)
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),
Expand Down Expand Up @@ -188,3 +196,11 @@ std::string Union::generateHelperClass() const {
}

std::string Union::getTypeAlias() const { return "union_" + name; }

bool Union::operator==(const Type &other) const {
auto *structOrUnion = dynamic_cast<const StructOrUnion *>(&other);
if (structOrUnion) {
return this->equals(*structOrUnion);
}
return false;
}
6 changes: 3 additions & 3 deletions bindgen/ir/Struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class StructOrUnion {

std::string getName() const;

bool operator==(const StructOrUnion &other) const;
bool equals(const StructOrUnion &other) const;

std::shared_ptr<Location> getLocation() const;

Expand Down Expand Up @@ -69,7 +69,7 @@ class Struct : public StructOrUnion,

std::string str() const override;

using StructOrUnion::operator==;
bool operator==(const Type &other) const override;

private:
/* type size is needed if number of fields is bigger than 22 */
Expand All @@ -87,7 +87,7 @@ class Union : public StructOrUnion,

std::string generateHelperClass() const override;

using StructOrUnion::operator==;
bool operator==(const Type &other) const override;

std::string getTypeAlias() const override;
};
Expand Down
3 changes: 3 additions & 0 deletions bindgen/ir/TypeAndName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ std::string TypeAndName::getName() const { return name; }
void TypeAndName::setType(std::shared_ptr<Type> type) { this->type = type; }

bool TypeAndName::operator==(const TypeAndName &other) const {
if (this == &other) {
return true;
}
return name == other.name && *type == *other.type;
}

Expand Down
8 changes: 5 additions & 3 deletions bindgen/ir/types/ArrayType.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "ArrayType.h"
#include "../../Utils.h"
#include "../Struct.h"

ArrayType::ArrayType(std::shared_ptr<Type> elementsType, uint64_t size)
: size(size), elementsType(std::move(elementsType)) {}
Expand All @@ -12,19 +13,20 @@ std::string ArrayType::str() const {
bool ArrayType::usesType(const std::shared_ptr<Type> &type,
bool stopOnTypeDefs) const {
return *elementsType == *type ||
elementsType.get()->usesType(type, stopOnTypeDefs);
elementsType->usesType(type, stopOnTypeDefs);
}

bool ArrayType::operator==(const Type &other) const {
if (this == &other) {
return true;
}
if (isInstanceOf<const ArrayType>(&other)) {
if (isInstanceOf<const ArrayType>(&other) &&
!isInstanceOf<const Union>(&other)) {
auto *arrayType = dynamic_cast<const ArrayType *>(&other);
if (size != arrayType->size) {
return false;
}
return *elementsType == *arrayType->elementsType.get();
return *elementsType == *arrayType->elementsType;
}
return false;
}
4 changes: 3 additions & 1 deletion bindgen/ir/types/PrimitiveType.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "PrimitiveType.h"
#include "../../Utils.h"
#include "../Enum.h"

PrimitiveType::PrimitiveType(std::string type) : type(std::move(type)) {}

Expand All @@ -16,7 +17,8 @@ bool PrimitiveType::operator==(const Type &other) const {
if (this == &other) {
return true;
}
if (isInstanceOf<const PrimitiveType>(&other)) {
if (isInstanceOf<const PrimitiveType>(&other) &&
!isInstanceOf<const Enum>(&other)) {
auto *primitiveType = dynamic_cast<const PrimitiveType *>(&other);
return type == primitiveType->type;
}
Expand Down
8 changes: 8 additions & 0 deletions tests/samples/IncludesHeader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "include/included.h"

size getSize(struct document *d);

struct courseInfo {
char *name;
enum semester s;
};
Loading

0 comments on commit 5447079

Please sign in to comment.