Skip to content
This repository was archived by the owner on Nov 8, 2024. It is now read-only.

Commit a6e5ee2

Browse files
authored
Add missing checks for circular references (#703)
2 parents f4d8c0b + 6e6e376 commit a6e5ee2

File tree

5 files changed

+567
-19
lines changed

5 files changed

+567
-19
lines changed

src/NamedTypesRegistry.cc

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -264,20 +264,24 @@ namespace drafter
264264

265265
bool hasAncestor(const snowcrash::DataStructure* object, const snowcrash::DataStructure* ancestor) const
266266
{
267-
std::string s = name(object);
268-
const std::string& isAncestor = name(ancestor);
267+
std::vector<std::string> symbols;
269268

270-
while (!s.empty()) {
271-
if (s == isAncestor) {
272-
return true;
273-
}
269+
const std::string& object_typename = name(object);
270+
const std::string& ancestor_typename = name(ancestor);
274271

275-
InheritanceMap::const_iterator i = childToParent.find(s);
276-
if (i == childToParent.end()) {
277-
return false;
278-
}
272+
auto current_typename = object_typename;
279273

280-
s = i->second;
274+
while (true) {
275+
if (current_typename == ancestor_typename)
276+
return true; // found ancestor (happy path)
277+
auto next_typename = childToParent.find(current_typename);
278+
if (next_typename == childToParent.end())
279+
return false; // arrived at the end
280+
281+
if (symbols.end() != std::find(symbols.begin(), symbols.end(), current_typename))
282+
return false; // circular reference
283+
symbols.emplace_back(current_typename);
284+
current_typename = next_typename->second;
281285
}
282286

283287
return false;

src/refract/ExpandVisitor.cc

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,18 +102,34 @@ namespace refract
102102
}
103103
};
104104

105+
template <typename It>
106+
std::reverse_iterator<It> make_reverse(It&& it)
107+
{
108+
return std::reverse_iterator<It>(std::forward<It>(it));
109+
}
110+
105111
std::unique_ptr<ExtendElement> GetInheritanceTree(const std::string& name, const Registry& registry)
106112
{
107-
std::stack<std::unique_ptr<IElement> > inheritance;
113+
using inheritance_map = std::vector<std::pair<std::string, std::unique_ptr<IElement> > >;
114+
115+
inheritance_map inheritance;
108116
std::string en = name;
109117

110-
// FIXME: add check against recursive inheritance
111118
// walk recursive in registry and expand inheritance tree
112119
for (const IElement* parent = registry.find(en); parent && !isReserved(en);
113120
en = parent->element(), parent = registry.find(en)) {
114121

115-
inheritance.push(clone(*parent, ((IElement::cAll ^ IElement::cElement) | IElement::cNoMetaId)));
116-
inheritance.top()->meta().set("ref", from_primitive(en));
122+
if (inheritance.end()
123+
!= std::find_if(inheritance.begin(), //
124+
inheritance.end(), //
125+
[en](const inheritance_map::value_type& other) { return en == other.first; })) //
126+
{
127+
return make_empty<ExtendElement>();
128+
}
129+
130+
inheritance.emplace_back(
131+
en, clone(*parent, ((IElement::cAll ^ IElement::cElement) | IElement::cNoMetaId)));
132+
inheritance.back().second->meta().set("ref", from_primitive(en));
117133
}
118134

119135
if (inheritance.empty())
@@ -122,10 +138,10 @@ namespace refract
122138
auto e = make_element<ExtendElement>();
123139
auto& content = e->get();
124140

125-
do {
126-
content.push_back(std::move(inheritance.top()));
127-
inheritance.pop();
128-
} while (!inheritance.empty());
141+
std::for_each( //
142+
make_reverse(inheritance.end()),
143+
make_reverse(inheritance.begin()),
144+
[&content](inheritance_map::value_type& entry) { content.push_back(std::move(entry.second)); });
129145

130146
// FIXME: posible solution while referenced type is not found in regisry
131147
// \see test/fixtures/mson-resource-unresolved-reference.apib

test/fixtures/api/issue-702.apib

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# API name
2+
3+
## Group Instances
4+
5+
### Instance Model [/{instance-id}]
6+
7+
8+
## Group Profiles
9+
10+
### Profiles Collection [/profiles]
11+
12+
#### Create Profile [POST]
13+
14+
+ Attributes (Profile)
15+
16+
+ Request (application/json)
17+
18+
+ Body
19+
20+
{}
21+
22+
+ Schema
23+
24+
{}
25+
26+
27+
### Profile [/v1/profiles/{id}]
28+
29+
+ Attributes (Profile)
30+

0 commit comments

Comments
 (0)