diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 241a80f46..e2e701542 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(solidity-upgrade solidityUpgrade/UpgradeSuite.h solidityUpgrade/Upgrade050.cpp solidityUpgrade/Upgrade060.cpp + solidityUpgrade/Upgrade070.cpp solidityUpgrade/SourceTransform.h solidityUpgrade/SourceUpgrade.cpp ) diff --git a/tools/solidityUpgrade/SourceTransform.h b/tools/solidityUpgrade/SourceTransform.h index 2b42471c1..b9250ae6a 100644 --- a/tools/solidityUpgrade/SourceTransform.h +++ b/tools/solidityUpgrade/SourceTransform.h @@ -19,17 +19,39 @@ #include +#include #include namespace solidity::tools { +/** + * Helper for displaying location during asserts + */ +class LocationHelper +{ + std::stringstream m_stream; + +public: + + template + LocationHelper& operator<<(T const& data) + { + m_stream << data; + return *this; + } + + operator std::string() { return m_stream.str(); } +}; + + /** * Helper that provides functions which analyze certain source locations * on a textual base. They utilize regular expression to search for * keywords or to determine formatting. */ -class SourceAnalysis { +class SourceAnalysis +{ public: static bool isMultilineKeyword( langutil::SourceLocation const& _location, @@ -82,6 +104,7 @@ public: for (auto inheritedContract: _contracts) overrideList += inheritedContract->name() + ","; + // Note: Can create incorrect replacements return "override(" + overrideList.substr(0, overrideList.size() - 1) + ")"; } }; @@ -102,11 +125,21 @@ public: std::string const& _expression ) { - return regex_replace( - _location.text(), - std::regex{"(\\b" + _keyword + "\\b)"}, - _expression + " " + _keyword - ); + auto _regex = std::regex{"(\\b" + _keyword + "\\b)"}; + if (regex_search(_location.text(), _regex)) + return regex_replace( + _location.text(), + _regex, + _expression + " " + _keyword + ); + else + solAssert( + false, + LocationHelper() << "Could not fix: " << _location.text() << " at " << _location << + "\nNeeds to be fixed manually." + ); + + return ""; } /// Searches for the keyword given and appends the expression. @@ -121,7 +154,17 @@ public: std::string toAppend = isMultiline ? ("\n " + _expression) : (" " + _expression); std::regex keyword{"(\\b" + _keyword + "\\b)"}; - return regex_replace(_location.text(), keyword, _keyword + toAppend); + if (regex_search(_location.text(), keyword)) + return regex_replace(_location.text(), keyword, _keyword + toAppend); + else + solAssert( + false, + LocationHelper() << "Could not fix: " << _location.text() << " at " << _location << + "\nNeeds to be fixed manually." + ); + + return ""; + } /// Searches for the first right parenthesis and appends the expression @@ -132,11 +175,21 @@ public: std::string const& _expression ) { - return regex_replace( - _location.text(), - std::regex{"(\\))"}, - ") " + _expression - ); + auto _regex = std::regex{"(\\))"}; + if (regex_search(_location.text(), _regex)) + return regex_replace( + _location.text(), + std::regex{"(\\))"}, + ") " + _expression + ); + else + solAssert( + false, + LocationHelper() << "Could not fix: " << _location.text() << " at " << _location << + "\nNeeds to be fixed manually." + ); + + return ""; } /// Searches for the `function` keyword and its identifier and replaces @@ -148,11 +201,71 @@ public: std::string const& _expression ) { - return regex_replace( - _location.text(), - std::regex{"(\\bfunction\\s*" + _name + "\\b)"}, - _expression - ); + auto _regex = std::regex{ "(\\bfunction\\s*" + _name + "\\b)"}; + if (regex_search(_location.text(), _regex)) + return regex_replace( + _location.text(), + _regex, + _expression + ); + else + solAssert( + false, + LocationHelper() << "Could not fix: " << _location.text() << " at " << _location << + "\nNeeds to be fixed manually." + ); + + return ""; + } + + static std::string gasUpdate(langutil::SourceLocation const& _location) + { + // dot, "gas", any number of whitespaces, left bracket + std::regex gasReg{"\\.gas\\s*\\("}; + + if (regex_search(_location.text(), gasReg)) + { + std::string out = regex_replace( + _location.text(), + gasReg, + "{gas: ", + std::regex_constants::format_first_only + ); + return regex_replace(out, std::regex{"\\)$"}, "}"); + } + else + solAssert( + false, + LocationHelper() << "Could not fix: " << _location.text() << " at " << _location << + "\nNeeds to be fixed manually." + ); + + return ""; + } + + static std::string valueUpdate(langutil::SourceLocation const& _location) + { + // dot, "value", any number of whitespaces, left bracket + std::regex valueReg{"\\.value\\s*\\("}; + + if (regex_search(_location.text(), valueReg)) + { + std::string out = regex_replace( + _location.text(), + valueReg, + "{value: ", + std::regex_constants::format_first_only + ); + return regex_replace(out, std::regex{"\\)$"}, "}"); + } + else + solAssert( + false, + LocationHelper() << "Could not fix: " << _location.text() << " at " << _location << + "\nNeeds to be fixed manually." + ); + + return ""; } }; diff --git a/tools/solidityUpgrade/SourceUpgrade.cpp b/tools/solidityUpgrade/SourceUpgrade.cpp index 8c05ecc9f..04f83eeee 100644 --- a/tools/solidityUpgrade/SourceUpgrade.cpp +++ b/tools/solidityUpgrade/SourceUpgrade.cpp @@ -194,6 +194,8 @@ Allowed options)", m_suite.activateModule(Module::OverridingFunction); else if (module == "virtual") m_suite.activateModule(Module::VirtualFunction); + else if (module == "dotsyntax") + m_suite.activateModule(Module::DotSyntax); else { error() << "Unknown upgrade module \"" + module + "\"" << endl; diff --git a/tools/solidityUpgrade/SourceUpgrade.h b/tools/solidityUpgrade/SourceUpgrade.h index 9ace60e57..9fb7a5ee2 100644 --- a/tools/solidityUpgrade/SourceUpgrade.h +++ b/tools/solidityUpgrade/SourceUpgrade.h @@ -1,4 +1,4 @@ -/* +/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,8 @@ private: VisibilitySpecifier, AbstractContract, OverridingFunction, - VirtualFunction + VirtualFunction, + DotSyntax }; /// Upgrade suite that hosts all available modules. @@ -78,6 +80,10 @@ private: OverridingFunction{m_changes}.analyze(_sourceUnit); if (isActivated(Module::VirtualFunction)) VirtualFunction{m_changes}.analyze(_sourceUnit); + + /// Solidity 0.7.0 + if (isActivated(Module::DotSyntax)) + DotSyntax{m_changes}.analyze(_sourceUnit); } void activateModule(Module _module) { m_modules.insert(_module); } @@ -96,7 +102,8 @@ private: Module::VisibilitySpecifier, Module::AbstractContract, Module::OverridingFunction, - Module::VirtualFunction + Module::VirtualFunction, + Module::DotSyntax }; }; diff --git a/tools/solidityUpgrade/Upgrade070.cpp b/tools/solidityUpgrade/Upgrade070.cpp new file mode 100644 index 000000000..c38ae2b97 --- /dev/null +++ b/tools/solidityUpgrade/Upgrade070.cpp @@ -0,0 +1,42 @@ +/* + 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. + +n You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +#include +#include + +using namespace solidity::frontend; +using namespace solidity::tools; + +void DotSyntax::endVisit(FunctionCall const& _functionCall) +{ + TypePointer type = _functionCall.annotation().type; + if (auto const funcType = dynamic_cast(type)) + { + if (funcType->valueSet()) + m_changes.emplace_back( + UpgradeChange::Level::Safe, + _functionCall.location(), + SourceTransform::valueUpdate(_functionCall.location()) + ); + + if (funcType->gasSet()) + m_changes.emplace_back( + UpgradeChange::Level::Safe, + _functionCall.location(), + SourceTransform::gasUpdate(_functionCall.location()) + ); + } +} diff --git a/tools/solidityUpgrade/Upgrade070.h b/tools/solidityUpgrade/Upgrade070.h new file mode 100644 index 000000000..29d689f97 --- /dev/null +++ b/tools/solidityUpgrade/Upgrade070.h @@ -0,0 +1,35 @@ +/* + 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 . +*/ +#pragma once + +#include + +#include + +namespace solidity::tools +{ + +class DotSyntax: public AnalysisUpgrade +{ +public: + using AnalysisUpgrade::AnalysisUpgrade; + void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); } +private: + void endVisit(frontend::FunctionCall const& _expression) override; +}; + +} diff --git a/tools/solidityUpgrade/main.cpp b/tools/solidityUpgrade/main.cpp index 0f2b7a473..9bbc3a0af 100644 --- a/tools/solidityUpgrade/main.cpp +++ b/tools/solidityUpgrade/main.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -74,8 +75,16 @@ int main(int argc, char** argv) if (!upgrade.parseArguments(argc, argv)) return 1; upgrade.printPrologue(); - if (!upgrade.processInput()) - return 1; + + try + { + if (!upgrade.processInput()) + return 1; + } + catch (boost::exception const& _exception) + { + cerr << "Exception while processing input: " << boost::diagnostic_information(_exception) << endl; + } return 0; }