Skip to content

Commit 36545f0

Browse files
committed
Fix detection of cyclic structs and unions
1 parent 9eb0ba5 commit 36545f0

29 files changed

+324
-201
lines changed

bindgen/CMakeLists.txt

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ add_executable(bindgen
3636
defines/DefineFinderActionFactory.h
3737
TypeTranslator.h
3838
TypeTranslator.cpp
39-
CycleDetection.h
4039
Utils.h
4140
ir/IR.h
4241
ir/IR.cpp

bindgen/CycleDetection.h

-61
This file was deleted.

bindgen/Utils.h

+10
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,14 @@ static inline bool isAliasForOpaqueType(const Type *type) {
142142
return false;
143143
}
144144

145+
static inline bool contains(const Type *type,
146+
std::vector<std::shared_ptr<const Type>> &types) {
147+
for (const auto &t : types) {
148+
if (*type == *t) {
149+
return true;
150+
}
151+
}
152+
return false;
153+
}
154+
145155
#endif // UTILS_H

bindgen/ir/Function.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,19 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) {
3131
return s;
3232
}
3333

34-
bool Function::usesType(std::shared_ptr<Type> type, bool stopOnTypeDefs) const {
35-
if (*retType == *type || retType->usesType(type, stopOnTypeDefs)) {
34+
bool Function::usesType(
35+
std::shared_ptr<Type> type, bool stopOnTypeDefs,
36+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
37+
visitedTypes.clear();
38+
if (*retType == *type ||
39+
retType.get()->usesType(type, stopOnTypeDefs, visitedTypes)) {
3640
return true;
3741
}
3842
for (const auto &parameter : parameters) {
43+
visitedTypes.clear();
3944
if (*parameter->getType() == *type ||
40-
parameter->getType()->usesType(type, stopOnTypeDefs)) {
45+
parameter->getType().get()->usesType(type, stopOnTypeDefs,
46+
visitedTypes)) {
4147
return true;
4248
}
4349
}

bindgen/ir/Function.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ class Function {
2121
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
2222
const Function &func);
2323

24-
bool usesType(std::shared_ptr<Type> type, bool stopOnTypeDefs) const;
24+
bool usesType(std::shared_ptr<Type> type, bool stopOnTypeDefs,
25+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
2526

2627
std::string getName() const;
2728

bindgen/ir/IR.cpp

+67-43
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,11 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
113113
<< "object " << objectName << " {\n";
114114
}
115115

116+
std::vector<std::shared_ptr<const Type>> visitedTypes;
117+
116118
for (const auto &typeDef : ir.typeDefs) {
117-
if (ir.shouldOutput(typeDef)) {
119+
visitedTypes.clear();
120+
if (ir.shouldOutput(typeDef, visitedTypes)) {
118121
s << *typeDef;
119122
} else if (isAliasForOpaqueType(typeDef.get()) &&
120123
ir.inMainFile(*typeDef)) {
@@ -177,7 +180,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
177180

178181
std::string sep = "";
179182
for (const auto &e : ir.enums) {
180-
if (ir.shouldOutput(e)) {
183+
visitedTypes.clear();
184+
if (ir.shouldOutput(e, visitedTypes)) {
181185
s << sep << *e;
182186
sep = "\n";
183187
}
@@ -190,13 +194,15 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
190194
s << "object " << ir.libName << "Helpers {\n";
191195

192196
for (const auto &st : ir.structs) {
193-
if (ir.shouldOutput(st) && st->hasHelperMethods()) {
197+
visitedTypes.clear();
198+
if (ir.shouldOutput(st, visitedTypes) && st->hasHelperMethods()) {
194199
s << "\n" << st->generateHelperClass();
195200
}
196201
}
197202

198203
for (const auto &u : ir.unions) {
199-
if (ir.shouldOutput(u) && u->hasHelperMethods()) {
204+
visitedTypes.clear();
205+
if (ir.shouldOutput(u, visitedTypes) && u->hasHelperMethods()) {
200206
s << "\n" << u->generateHelperClass();
201207
}
202208
}
@@ -216,14 +222,17 @@ void IR::generate(const std::string &excludePrefix) {
216222
}
217223

218224
bool IR::hasHelperMethods() const {
225+
std::vector<std::shared_ptr<const Type>> visitedTypes;
219226
for (const auto &u : unions) {
220-
if (shouldOutput(u) && u->hasHelperMethods()) {
227+
visitedTypes.clear();
228+
if (shouldOutput(u, visitedTypes) && u->hasHelperMethods()) {
221229
return true;
222230
}
223231
}
224232

225233
for (const auto &s : structs) {
226-
if (shouldOutput(s) && s->hasHelperMethods()) {
234+
visitedTypes.clear();
235+
if (shouldOutput(s, visitedTypes) && s->hasHelperMethods()) {
227236
return true;
228237
}
229238
}
@@ -272,8 +281,10 @@ void IR::replaceTypeInTypeDefs(std::shared_ptr<Type> oldType,
272281
template <typename T>
273282
bool IR::isTypeUsed(const std::vector<T> &declarations,
274283
std::shared_ptr<Type> type, bool stopOnTypeDefs) const {
284+
std::vector<std::shared_ptr<const Type>> visitedTypes;
275285
for (const auto &decl : declarations) {
276-
if (decl->usesType(type, stopOnTypeDefs)) {
286+
visitedTypes.clear();
287+
if (decl->usesType(type, stopOnTypeDefs, visitedTypes)) {
277288
return true;
278289
}
279290
}
@@ -289,46 +300,55 @@ bool IR::typeIsUsedOnlyInTypeDefs(const std::shared_ptr<Type> &type) const {
289300
isTypeUsed(literalDefines, type, true));
290301
}
291302

292-
bool IR::isTypeUsed(const std::shared_ptr<Type> &type,
293-
bool checkRecursively) const {
294-
if (checkRecursively) {
295-
if (isTypeUsed(functions, type, true) ||
296-
isTypeUsed(variables, type, true) ||
297-
isTypeUsed(literalDefines, type, true)) {
298-
return true;
299-
}
300-
/* type is used if there exists another type that is used and that
301-
* references this type */
302-
for (const auto &typeDef : typeDefs) {
303-
if (typeDef->usesType(type, false)) {
304-
if (shouldOutput(typeDef)) {
305-
return true;
306-
}
303+
bool IR::isTypeUsed(
304+
const std::shared_ptr<Type> &type,
305+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
306+
if (contains(type.get(), visitedTypes)) {
307+
return false;
308+
}
309+
visitedTypes.push_back(type);
310+
if (isTypeUsed(functions, type, true) ||
311+
isTypeUsed(variables, type, true) ||
312+
isTypeUsed(literalDefines, type, true)) {
313+
return true;
314+
}
315+
/* type is used if there exists another type that is used and that
316+
* references this type */
317+
std::vector<std::shared_ptr<const Type>> visitedTypesInner;
318+
for (const auto &typeDef : typeDefs) {
319+
visitedTypesInner.clear();
320+
if (typeDef->usesType(type, false, visitedTypesInner)) {
321+
if (shouldOutput(typeDef, visitedTypes)) {
322+
return true;
307323
}
308324
}
309-
for (const auto &s : structs) {
310-
/* stopOnTypeDefs parameter is true because because typedefs were
311-
* checked */
312-
if (s->usesType(type, true)) {
313-
if (shouldOutput(s)) {
314-
return true;
315-
}
325+
}
326+
for (const auto &s : structs) {
327+
/* stopOnTypeDefs parameter is true because because typedefs were
328+
* checked */
329+
visitedTypesInner.clear();
330+
if (s->usesType(type, true, visitedTypesInner)) {
331+
if (shouldOutput(s, visitedTypes)) {
332+
return true;
316333
}
317334
}
318-
for (const auto &u : unions) {
319-
/* stopOnTypeDefs parameter is true because because typedefs were
320-
* checked */
321-
if (u->usesType(type, true)) {
322-
if (shouldOutput(u)) {
323-
return true;
324-
}
335+
}
336+
for (const auto &u : unions) {
337+
/* stopOnTypeDefs parameter is true because because typedefs were
338+
* checked */
339+
visitedTypesInner.clear();
340+
if (u->usesType(type, true, visitedTypesInner)) {
341+
if (shouldOutput(u, visitedTypes)) {
342+
return true;
325343
}
326344
}
327-
return false;
328-
} else {
329-
return !(typeIsUsedOnlyInTypeDefs(type) &&
330-
!isTypeUsed(typeDefs, type, false));
331345
}
346+
return false;
347+
}
348+
349+
bool IR::isTypeUsed(const std::shared_ptr<Type> &type) const {
350+
return !(typeIsUsedOnlyInTypeDefs(type) &&
351+
!isTypeUsed(typeDefs, type, false));
332352
}
333353

334354
void IR::setScalaNames() {
@@ -460,17 +480,21 @@ template <typename T> bool IR::inMainFile(const T &type) const {
460480
template <typename T>
461481
bool IR::hasOutputtedDeclaration(
462482
const std::vector<std::shared_ptr<T>> &declarations) const {
483+
std::vector<std::shared_ptr<const Type>> visitedTypes;
463484
for (const auto &declaration : declarations) {
464-
if (shouldOutput(declaration)) {
485+
visitedTypes.clear();
486+
if (shouldOutput(declaration, visitedTypes)) {
465487
return true;
466488
}
467489
}
468490
return false;
469491
}
470492

471493
template <typename T>
472-
bool IR::shouldOutput(const std::shared_ptr<T> &type) const {
473-
if (isTypeUsed(type, true)) {
494+
bool IR::shouldOutput(
495+
const std::shared_ptr<T> &type,
496+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
497+
if (isTypeUsed(type, visitedTypes)) {
474498
return true;
475499
}
476500
if (!inMainFile(*type)) {

bindgen/ir/IR.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,16 @@ class IR {
121121
* output false if the type is used only in unused types
122122
* @return true if type is used in one of declarations
123123
*/
124-
bool isTypeUsed(const std::shared_ptr<Type> &type,
125-
bool checkRecursively = false) const;
124+
bool
125+
isTypeUsed(const std::shared_ptr<Type> &type,
126+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
127+
128+
/**
129+
* @param checkRecursively if this parameter is true then the method will
130+
* output false if the type is used only in unused types
131+
* @return true if type is used in one of declarations
132+
*/
133+
bool isTypeUsed(const std::shared_ptr<Type> &type) const;
126134

127135
/**
128136
* @return true if type is used in one of given declarations.
@@ -158,7 +166,9 @@ class IR {
158166
* message is printed when bindings are generated)
159167
*/
160168
template <typename T>
161-
bool shouldOutput(const std::shared_ptr<T> &type) const;
169+
bool
170+
shouldOutput(const std::shared_ptr<T> &type,
171+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
162172

163173
/**
164174
* @tparam T Struct or Union

bindgen/ir/LiteralDefine.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
1111
return s;
1212
}
1313

14-
bool LiteralDefine::usesType(const std::shared_ptr<Type> &type,
15-
bool stopOnTypeDefs) const {
16-
return *this->type == *type ||
17-
this->type.get()->usesType(type, stopOnTypeDefs);
14+
bool LiteralDefine::usesType(
15+
const std::shared_ptr<const Type> &type, bool stopOnTypeDefs,
16+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
17+
if (*this->type == *type) {
18+
return true;
19+
}
20+
visitedTypes.clear();
21+
return this->type->usesType(type, stopOnTypeDefs, visitedTypes);
1822
}

bindgen/ir/LiteralDefine.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class LiteralDefine : public Define {
1313
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s,
1414
const LiteralDefine &literalDefine);
1515

16-
bool usesType(const std::shared_ptr<Type> &type, bool stopOnTypeDefs) const;
16+
bool usesType(const std::shared_ptr<const Type> &type, bool stopOnTypeDefs,
17+
std::vector<std::shared_ptr<const Type>> &visitedTypes) const;
1718

1819
private:
1920
std::string literal;

0 commit comments

Comments
 (0)