/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ #include #include #include #include #include #include using namespace std; using namespace dev; using namespace dev::yul; using dev::solidity::assembly::TypedName; using dev::solidity::assembly::TypedNameList; void VarDeclPropagator::operator()(Block& _block) { map outerEmptyVarDecls; map outerLazyInitializedVarDecls; swap(m_emptyVarDecls, outerEmptyVarDecls); swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls); ASTModifier::operator()(_block); iterateReplacing( _block.statements, [this](Statement& _stmt) -> boost::optional> { if (_stmt.type() == typeid(VariableDeclaration)) { VariableDeclaration& varDecl = boost::get(_stmt); boost::remove_erase_if( varDecl.variables, [&](TypedName const& _typedName) { return m_lazyInitializedVarDecls.count(_typedName.name); } ); if (varDecl.variables.empty()) return vector{}; else return {}; } else if (_stmt.type() == typeid(Assignment)) { Assignment& assignment = boost::get(_stmt); if (isFullyLazyInitialized(assignment.variableNames)) return vector{recreateVariableDeclaration(assignment)}; else return {}; } else return {}; } ); swap(m_emptyVarDecls, outerEmptyVarDecls); swap(m_lazyInitializedVarDecls, outerLazyInitializedVarDecls); } void VarDeclPropagator::operator()(VariableDeclaration& _varDecl) { if (_varDecl.value) visit(*_varDecl.value); else for (TypedName const& typedName: _varDecl.variables) m_emptyVarDecls[typedName.name] = typedName; } void VarDeclPropagator::operator()(Assignment& _assignment) { visit(*_assignment.value); if (allVarNamesUninitialized(_assignment.variableNames)) for (Identifier const& ident: _assignment.variableNames) m_lazyInitializedVarDecls[ident.name] = m_emptyVarDecls[ident.name]; for (Identifier& name: _assignment.variableNames) (*this)(name); } void VarDeclPropagator::operator()(Identifier& _ident) { m_emptyVarDecls.erase(_ident.name); } bool VarDeclPropagator::allVarNamesUninitialized(vector const& _variableNames) const { return all_of( begin(_variableNames), end(_variableNames), [&](Identifier const& _ident) -> bool { return m_emptyVarDecls.count(_ident.name); } ); } bool VarDeclPropagator::isFullyLazyInitialized(vector const& _variableNames) const { return all_of( begin(_variableNames), end(_variableNames), [&](Identifier const& ident) -> bool { return m_lazyInitializedVarDecls.count(ident.name); } ); } VariableDeclaration VarDeclPropagator::recreateVariableDeclaration(Assignment& _assignment) { TypedNameList variables; for (Identifier const& varName: _assignment.variableNames) { variables.emplace_back(move(m_lazyInitializedVarDecls.at(varName.name))); m_lazyInitializedVarDecls.erase(varName.name); } return VariableDeclaration{move(_assignment.location), move(variables), std::move(_assignment.value)}; }