Make Group searching robust for cyclic dependencies. fixes #0002567
This commit is contained in:
@@ -167,15 +167,28 @@ DocumentObject *GroupExtension::getObject(const char *Name) const
|
||||
|
||||
bool GroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
|
||||
{
|
||||
|
||||
if(obj == getExtendedObject())
|
||||
return false;
|
||||
|
||||
const std::vector<DocumentObject*>& grp = Group.getValues();
|
||||
for (std::vector<DocumentObject*>::const_iterator it = grp.begin(); it != grp.end(); ++it) {
|
||||
if (*it == obj) {
|
||||
for (auto child : grp) {
|
||||
|
||||
if(!child)
|
||||
continue;
|
||||
|
||||
if (child == obj) {
|
||||
return true;
|
||||
} else if ( recursive && (*it)->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
|
||||
} else if (child == getExtendedObject()) {
|
||||
Base::Exception("Cyclic dependencies detected: Search cannot be performed");
|
||||
} else if ( recursive && child->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
|
||||
|
||||
App::GroupExtension *subGroup = static_cast<App::GroupExtension *> (
|
||||
(*it)->getExtension(GroupExtension::getExtensionClassTypeId()));
|
||||
child->getExtension(GroupExtension::getExtensionClassTypeId()));
|
||||
std::vector<const GroupExtension*> history;
|
||||
history.push_back(this);
|
||||
|
||||
if (subGroup->hasObject (obj, recursive)) {
|
||||
if (subGroup->recursiveHasObject (obj, subGroup, history)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -184,22 +197,45 @@ bool GroupExtension::hasObject(const DocumentObject* obj, bool recursive) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GroupExtension::isChildOf(const GroupExtension* group) const
|
||||
{
|
||||
const std::vector<DocumentObject*>& grp = group->Group.getValues();
|
||||
for (std::vector<DocumentObject*>::const_iterator it = grp.begin(); it != grp.end(); ++it) {
|
||||
if (*it == getExtendedObject())
|
||||
return true;
|
||||
if ((*it)->hasExtension(GroupExtension::getExtensionClassTypeId())) {
|
||||
if (this->isChildOf(static_cast<GroupExtension*>((*it)->getExtension(GroupExtension::getExtensionClassTypeId()))))
|
||||
bool GroupExtension::recursiveHasObject(const DocumentObject* obj, const GroupExtension* group,
|
||||
std::vector< const GroupExtension* > history) const {
|
||||
|
||||
//the purpose is to prevent infinite recursion when groups form a cyclic graph. To do this
|
||||
//we store every group we processed on the current leave of the tree, and if we reach an
|
||||
//already processed group we know that it not really is a tree but a cycle.
|
||||
|
||||
history.push_back(this);
|
||||
|
||||
for (auto child : group->Group.getValues()) {
|
||||
|
||||
if(!child)
|
||||
continue;
|
||||
|
||||
if (child == obj) {
|
||||
return true;
|
||||
} else if ( child->hasExtension(GroupExtension::getExtensionClassTypeId()) ) {
|
||||
|
||||
auto ext = child->getExtensionByType<GroupExtension>();
|
||||
|
||||
if(std::find(history.begin(), history.end(), ext) != history.end())
|
||||
Base::Exception("Cyclic dependencies detected: Search cannot be performed");
|
||||
|
||||
if (recursiveHasObject(obj, ext, history)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool GroupExtension::isChildOf(const GroupExtension* group, bool recursive) const
|
||||
{
|
||||
return group->hasObject(getExtendedObject(), recursive);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<DocumentObject*> GroupExtension::getObjects() const
|
||||
{
|
||||
return Group.getValues();
|
||||
|
||||
Reference in New Issue
Block a user