Skip to content

Commit 5447079

Browse files
committed
Add tests. Search for type usages recursively
1 parent 902fa75 commit 5447079

File tree

12 files changed

+209
-70
lines changed

12 files changed

+209
-70
lines changed

bindgen/ir/IR.cpp

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void IR::addVarDefine(std::string name, std::shared_ptr<Variable> variable) {
7878
}
7979

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

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

110110
for (const auto &typeDef : ir.typeDefs) {
111-
if (ir.typeDefInMainFile(*typeDef) || ir.isTypeUsed(typeDef)) {
111+
if (ir.isOutputted(typeDef)) {
112112
s << *typeDef;
113113
}
114114
}
@@ -136,18 +136,16 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
136136
s << "}\n\n";
137137
}
138138

139-
if (ir.hasOutputtedEnums() || ir.hasHelperMethods()) {
139+
if (ir.hasOutputtedDeclaration(ir.enums) || ir.hasHelperMethods()) {
140140
s << "import " << objectName << "._\n\n";
141141
}
142142

143-
if (ir.hasOutputtedEnums()) {
143+
if (ir.hasOutputtedDeclaration(ir.enums)) {
144144
s << "object " << ir.libName << "Enums {\n";
145145

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

162160
for (const auto &st : ir.structs) {
163-
if (ir.isOutputted(st.get()) && st->hasHelperMethods()) {
161+
if (ir.isOutputted(st) && st->hasHelperMethods()) {
164162
s << "\n" << st->generateHelperClass();
165163
}
166164
}
167165

168166
for (const auto &u : ir.unions) {
169-
if (ir.isOutputted(u.get())) {
167+
if (ir.isOutputted(u)) {
170168
s << "\n" << u->generateHelperClass();
171169
}
172170
}
@@ -193,7 +191,7 @@ bool IR::hasHelperMethods() const {
193191
}
194192

195193
for (const auto &s : structs) {
196-
if (isOutputted(s.get()) && s->hasHelperMethods()) {
194+
if (isOutputted(s) && s->hasHelperMethods()) {
197195
return true;
198196
}
199197
}
@@ -259,9 +257,46 @@ bool IR::typeIsUsedOnlyInTypeDefs(const std::shared_ptr<Type> &type) const {
259257
isTypeUsed(literalDefines, type, true));
260258
}
261259

262-
bool IR::isTypeUsed(const std::shared_ptr<Type> &type) const {
263-
return !(typeIsUsedOnlyInTypeDefs(type) &&
264-
!isTypeUsed(typeDefs, type, false));
260+
bool IR::isTypeUsed(const std::shared_ptr<Type> &type,
261+
bool checkRecursively) const {
262+
if (checkRecursively) {
263+
if (isTypeUsed(functions, type, true) ||
264+
isTypeUsed(variables, type, true) ||
265+
isTypeUsed(literalDefines, type, true)) {
266+
return true;
267+
}
268+
/* type is used if there exists another type that is used and that
269+
* references this type */
270+
for (const auto &typeDef : typeDefs) {
271+
if (typeDef->usesType(type, false)) {
272+
if (isOutputted(typeDef)) {
273+
return true;
274+
}
275+
}
276+
}
277+
for (const auto &s : structs) {
278+
/* stopOnTypeDefs parameter is true because because typedefs were
279+
* checked */
280+
if (s->usesType(type, true)) {
281+
if (isOutputted(s)) {
282+
return true;
283+
}
284+
}
285+
}
286+
for (const auto &u : unions) {
287+
/* stopOnTypeDefs parameter is true because because typedefs were
288+
* checked */
289+
if (u->usesType(type, true)) {
290+
if (isOutputted(u)) {
291+
return true;
292+
}
293+
}
294+
}
295+
return false;
296+
} else {
297+
return !(typeIsUsedOnlyInTypeDefs(type) &&
298+
!isTypeUsed(typeDefs, type, false));
299+
}
265300
}
266301

267302
void IR::setScalaNames() {
@@ -370,60 +405,38 @@ IR::~IR() {
370405
varDefines.clear();
371406
}
372407

373-
bool IR::typeDefInMainFile(const TypeDef &typeDef) const {
374-
if (inMainFile(typeDef)) {
375-
return true;
376-
}
377-
Type *type = typeDef.getType().get();
378-
if (isInstanceOf<Struct>(type)) {
379-
return inMainFile(*dynamic_cast<Struct *>(type));
380-
}
381-
if (isInstanceOf<Union>(type)) {
382-
return inMainFile(*dynamic_cast<Union *>(type));
383-
}
384-
if (isInstanceOf<Enum>(type)) {
385-
return inMainFile(*dynamic_cast<Enum *>(type));
386-
}
387-
return false;
388-
}
389-
390408
template <typename T> bool IR::inMainFile(const T &type) const {
391409
std::shared_ptr<Location> location = type.getLocation();
392-
return location && locationManager.inMainFile(*location);
393-
}
394-
395-
bool IR::hasOutputtedEnums() const {
396-
for (const auto &e : enums) {
397-
if (inMainFile(*e) ||
398-
(!e->isAnonymous() &&
399-
isTypeUsed(getTypeDefWithName(e->getTypeAlias())))) {
400-
return true;
410+
if (!location) {
411+
/* generated TypeDef */
412+
auto *typeDef = dynamic_cast<const TypeDef *>(&type);
413+
assert(typeDef);
414+
Type *innerType = typeDef->getType().get();
415+
if (isInstanceOf<Struct>(innerType)) {
416+
return inMainFile(*dynamic_cast<Struct *>(innerType));
401417
}
402-
}
403-
return false;
404-
}
405-
406-
bool IR::hasOutputtedTypeDefs() const {
407-
for (const auto &typeDef : typeDefs) {
408-
if (inMainFile(*typeDef) || isTypeUsed(typeDef)) {
409-
return true;
418+
if (isInstanceOf<Union>(innerType)) {
419+
return inMainFile(*dynamic_cast<Union *>(innerType));
420+
}
421+
if (isInstanceOf<Enum>(innerType)) {
422+
return inMainFile(*dynamic_cast<Enum *>(innerType));
410423
}
411424
}
412-
return false;
425+
return location && locationManager.inMainFile(*location);
413426
}
414427

415428
template <typename T>
416429
bool IR::hasOutputtedDeclaration(
417430
const std::vector<std::shared_ptr<T>> &declarations) const {
418431
for (const auto &declaration : declarations) {
419-
if (isOutputted(declaration.get())) {
432+
if (isOutputted(declaration)) {
420433
return true;
421434
}
422435
}
423436
return false;
424437
}
425438

426-
bool IR::isOutputted(const StructOrUnion *structOrUnion) const {
427-
return inMainFile(*structOrUnion) ||
428-
isTypeUsed(getTypeDefWithName(structOrUnion->getTypeAlias()));
439+
template <typename T>
440+
bool IR::isOutputted(const std::shared_ptr<T> &type) const {
441+
return inMainFile(*type) || isTypeUsed(type, true);
429442
}

bindgen/ir/IR.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,12 @@ class IR {
115115
bool typeIsUsedOnlyInTypeDefs(const std::shared_ptr<Type> &type) const;
116116

117117
/**
118+
* @param checkRecursively if this parameter is true then the method will
119+
* output false if the type is used only in unused types
118120
* @return true if type is used in one of declarations
119121
*/
120-
bool isTypeUsed(const std::shared_ptr<Type> &type) const;
122+
bool isTypeUsed(const std::shared_ptr<Type> &type,
123+
bool checkRecursively = false) const;
121124

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

144-
bool typeDefInMainFile(const TypeDef &typeDef) const;
145-
146147
template <typename T> bool inMainFile(const T &type) const;
147148

148-
bool hasOutputtedEnums() const;
149-
150-
bool hasOutputtedTypeDefs() const;
151-
152-
bool isOutputted(const StructOrUnion *structOrUnion) const;
149+
/**
150+
* @tparam T Type subclass
151+
* @return true if type is in main file or it is used by declaration from
152+
* main file.
153+
*/
154+
template <typename T>
155+
bool isOutputted(const std::shared_ptr<T> &type) const;
153156

154157
/**
155158
* @tparam T Struct or Union

bindgen/ir/Location.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ Location::Location(std::string path, int lineNumber)
44
: path(std::move(path)), lineNumber(lineNumber) {}
55

66
std::string Location::getPath() const { return path; }
7+
8+
int Location::getLineNumber() const { return lineNumber; }

bindgen/ir/Location.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class Location {
99

1010
std::string getPath() const;
1111

12+
int getLineNumber() const;
13+
1214
private:
1315
std::string path;
1416
int lineNumber;

bindgen/ir/Struct.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ StructOrUnion::~StructOrUnion() {
5151
}
5252
}
5353

54-
bool StructOrUnion::operator==(const StructOrUnion &other) const {
54+
bool StructOrUnion::equals(const StructOrUnion &other) const {
5555
if (this == &other) {
5656
return true;
5757
}
@@ -94,7 +94,7 @@ std::shared_ptr<TypeDef> Struct::generateTypeDef() {
9494
getTypeAlias(),
9595
std::make_shared<ArrayType>(std::make_shared<PrimitiveType>("Byte"),
9696
typeSize),
97-
std::move(location));
97+
location);
9898
}
9999
}
100100

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

158+
bool Struct::operator==(const Type &other) const {
159+
auto *structOrUnion = dynamic_cast<const StructOrUnion *>(&other);
160+
if (structOrUnion) {
161+
return this->equals(*structOrUnion);
162+
}
163+
return false;
164+
}
165+
158166
Union::Union(std::string name, std::vector<Field *> fields, uint64_t maxSize,
159167
std::shared_ptr<Location> location)
160168
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),
@@ -188,3 +196,11 @@ std::string Union::generateHelperClass() const {
188196
}
189197

190198
std::string Union::getTypeAlias() const { return "union_" + name; }
199+
200+
bool Union::operator==(const Type &other) const {
201+
auto *structOrUnion = dynamic_cast<const StructOrUnion *>(&other);
202+
if (structOrUnion) {
203+
return this->equals(*structOrUnion);
204+
}
205+
return false;
206+
}

bindgen/ir/Struct.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class StructOrUnion {
3131

3232
std::string getName() const;
3333

34-
bool operator==(const StructOrUnion &other) const;
34+
bool equals(const StructOrUnion &other) const;
3535

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

@@ -69,7 +69,7 @@ class Struct : public StructOrUnion,
6969

7070
std::string str() const override;
7171

72-
using StructOrUnion::operator==;
72+
bool operator==(const Type &other) const override;
7373

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

8888
std::string generateHelperClass() const override;
8989

90-
using StructOrUnion::operator==;
90+
bool operator==(const Type &other) const override;
9191

9292
std::string getTypeAlias() const override;
9393
};

bindgen/ir/TypeAndName.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ std::string TypeAndName::getName() const { return name; }
1111
void TypeAndName::setType(std::shared_ptr<Type> type) { this->type = type; }
1212

1313
bool TypeAndName::operator==(const TypeAndName &other) const {
14+
if (this == &other) {
15+
return true;
16+
}
1417
return name == other.name && *type == *other.type;
1518
}
1619

bindgen/ir/types/ArrayType.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "ArrayType.h"
22
#include "../../Utils.h"
3+
#include "../Struct.h"
34

45
ArrayType::ArrayType(std::shared_ptr<Type> elementsType, uint64_t size)
56
: size(size), elementsType(std::move(elementsType)) {}
@@ -12,19 +13,20 @@ std::string ArrayType::str() const {
1213
bool ArrayType::usesType(const std::shared_ptr<Type> &type,
1314
bool stopOnTypeDefs) const {
1415
return *elementsType == *type ||
15-
elementsType.get()->usesType(type, stopOnTypeDefs);
16+
elementsType->usesType(type, stopOnTypeDefs);
1617
}
1718

1819
bool ArrayType::operator==(const Type &other) const {
1920
if (this == &other) {
2021
return true;
2122
}
22-
if (isInstanceOf<const ArrayType>(&other)) {
23+
if (isInstanceOf<const ArrayType>(&other) &&
24+
!isInstanceOf<const Union>(&other)) {
2325
auto *arrayType = dynamic_cast<const ArrayType *>(&other);
2426
if (size != arrayType->size) {
2527
return false;
2628
}
27-
return *elementsType == *arrayType->elementsType.get();
29+
return *elementsType == *arrayType->elementsType;
2830
}
2931
return false;
3032
}

bindgen/ir/types/PrimitiveType.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "PrimitiveType.h"
22
#include "../../Utils.h"
3+
#include "../Enum.h"
34

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

@@ -16,7 +17,8 @@ bool PrimitiveType::operator==(const Type &other) const {
1617
if (this == &other) {
1718
return true;
1819
}
19-
if (isInstanceOf<const PrimitiveType>(&other)) {
20+
if (isInstanceOf<const PrimitiveType>(&other) &&
21+
!isInstanceOf<const Enum>(&other)) {
2022
auto *primitiveType = dynamic_cast<const PrimitiveType *>(&other);
2123
return type == primitiveType->type;
2224
}

tests/samples/IncludesHeader.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include "include/included.h"
2+
3+
size getSize(struct document *d);
4+
5+
struct courseInfo {
6+
char *name;
7+
enum semester s;
8+
};

0 commit comments

Comments
 (0)