diff --git a/libyul/Object.cpp b/libyul/Object.cpp index 5c03c3b8c..247a90a5b 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -144,8 +144,36 @@ std::set Object::qualifiedDataNames() const return qualifiedNames; } +void Object::traverseObjectTree(Object const* _object, YulString _qualifiedName, std::function _visitor) +{ + yulAssert(!_qualifiedName.empty(), ""); + + std::vector subObjectPathComponents; + boost::algorithm::split(subObjectPathComponents, _qualifiedName.str(), boost::is_any_of(".")); + + for (std::string const& currentSubObjectName: subObjectPathComponents) + { + yulAssert(!currentSubObjectName.empty(), ""); + + auto subObjectIt = ranges::find_if( + _object->subObjects, + [¤tSubObjectName](auto const& _subObject) { return _subObject->name.str() == currentSubObjectName; } + ); + + if (subObjectIt != _object->subObjects.end()) + { + _object = dynamic_cast(subObjectIt->get()); + yulAssert(_object, "Assembly object <" + _object->name.str() + "> not found or does not contain code."); + yulAssert(_object->subId != std::numeric_limits::max(), ""); + if (_visitor(_object)) + break; + } + } +} + std::vector Object::pathToSubObject(YulString _qualifiedName) const { + std::vector path; yulAssert(_qualifiedName != name, ""); yulAssert(subIndexByName.count(name) == 0, ""); @@ -153,49 +181,24 @@ std::vector Object::pathToSubObject(YulString _qualifiedName) const _qualifiedName = YulString{_qualifiedName.str().substr(name.str().length() + 1)}; yulAssert(!_qualifiedName.empty(), ""); - std::vector subObjectPathComponents; - boost::algorithm::split(subObjectPathComponents, _qualifiedName.str(), boost::is_any_of(".")); - - std::vector path; - Object const* object = this; - for (std::string const& currentSubObjectName: subObjectPathComponents) - { - yulAssert(!currentSubObjectName.empty(), ""); - auto subIndexIt = object->subIndexByName.find(YulString{currentSubObjectName}); - yulAssert( - subIndexIt != object->subIndexByName.end(), - "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code." - ); - object = dynamic_cast(object->subObjects[subIndexIt->second].get()); - yulAssert(object, "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code."); - yulAssert(object->subId != std::numeric_limits::max(), ""); - path.push_back({object->subId}); - } - + traverseObjectTree(this, _qualifiedName, [&](Object const* _object) -> bool { + path.push_back({_object->subId}); + return false; + }); return path; } -shared_ptr Object::objectAt(shared_ptr const& _object, string const& _qualifiedName) +std::shared_ptr Object::objectAt(std::shared_ptr const& _object, std::string const& _qualifiedName) { - if (_qualifiedName.empty() || _qualifiedName == _object->name.str()) - return _object; + std::shared_ptr object = nullptr; + traverseObjectTree(_object.get(), YulString(_qualifiedName), [&](Object const* _obj) -> bool { + if (_qualifiedName.empty() || _qualifiedName == _obj->name.str()) + { + object = std::make_shared(*_obj); + return true; + } + return false; + }); - if (!boost::algorithm::starts_with(_qualifiedName, _object->name.str() + ".")) - return nullptr; - - string const subObjectPath = _qualifiedName.substr(_object->name.str().length() + 1); - string const subObjectName = subObjectPath.substr(0, subObjectPath.find_first_of('.')); - - auto subObjectIt = ranges::find_if( - _object->subObjects, - [&subObjectName](auto const& _subObject) { return _subObject->name.str() == subObjectName; } - ); - - if (subObjectIt == _object->subObjects.end()) - return nullptr; - - auto subObject = dynamic_pointer_cast(*subObjectIt); - yulAssert(subObject, "Assembly object <" + subObject->name.str() + "> does not contain code."); - - return objectAt(subObject, subObjectPath); + return object; } diff --git a/libyul/Object.h b/libyul/Object.h index fc824a785..d37d6c70b 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -117,6 +117,14 @@ public: /// The path must not lead to a @a Data object (will throw in that case). std::vector pathToSubObject(YulString _qualifiedName) const; + /// Traverses the @a _object tree applying the function @a _visitor at every subobject + /// in the path given by the @a _qualifiedName. + static void traverseObjectTree( + Object const* _object, + YulString _qualifiedName, + std::function _visitor + ); + /// sub id for object if it is subobject of another object, max value if it is not subobject size_t subId = std::numeric_limits::max(); @@ -130,7 +138,7 @@ public: /// @returns the name of the special metadata data object. static std::string metadataName() { return ".metadata"; } - /// Recursively searches for an Object at @param _qualifiedName within @param _object. + /// Searches for an Object at @param _qualifiedName within @param _object. /// @returns a shared_ptr to the Object or a nullptr if it was not found. static std::shared_ptr objectAt( std::shared_ptr const& _object,