mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7914 from ethereum/solidity-upgrade-basic
[tools] Create solidity-upgrade
This commit is contained in:
commit
f44188abf5
@ -62,6 +62,11 @@ defaults:
|
||||
path: build/solc/solc
|
||||
destination: solc
|
||||
|
||||
# compiled tool executable target
|
||||
- artifacts_tools: &artifacts_tools
|
||||
path: build/tools/solidity-upgrade
|
||||
destination: solidity-upgrade
|
||||
|
||||
# compiled executable targets
|
||||
- artifacts_executables: &artifacts_executables
|
||||
root: build
|
||||
@ -324,6 +329,7 @@ jobs:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- store_artifacts: *artifacts_tools
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
|
||||
b_ubu_release: &build_ubuntu1904_release
|
||||
@ -455,6 +461,7 @@ jobs:
|
||||
- /usr/local/Homebrew
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- store_artifacts: *artifacts_tools
|
||||
- persist_to_workspace: *artifacts_build_dir
|
||||
|
||||
t_osx_soltest:
|
||||
|
@ -55,6 +55,7 @@ add_subdirectory(libevmasm)
|
||||
add_subdirectory(libyul)
|
||||
add_subdirectory(libsolidity)
|
||||
add_subdirectory(libsolc)
|
||||
add_subdirectory(tools)
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
add_subdirectory(solc)
|
||||
|
@ -474,3 +474,240 @@ Error types
|
||||
11. ``CompilerError``: Invalid use of the compiler stack - this should be reported as an issue.
|
||||
12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue.
|
||||
13. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible.
|
||||
|
||||
|
||||
.. _compiler-tools:
|
||||
|
||||
Compiler tools
|
||||
**************
|
||||
|
||||
solidity-upgrade
|
||||
----------------
|
||||
|
||||
``solidity-upgrade`` can help you to semi-automatically upgrade your contracts
|
||||
to breaking language changes. While it does not and cannot implement all
|
||||
required changes for every breaking release, it still supports the ones, that
|
||||
would need plenty of repetitive manual adjustments otherwise.
|
||||
|
||||
.. note::
|
||||
|
||||
``solidity-upgrade`` carries out a large part of the work, but your
|
||||
contracts will most likely need further manual adjustments. We recommend
|
||||
using a version control system for your files. This helps reviewing and
|
||||
eventually rolling back the changes made.
|
||||
|
||||
.. warning::
|
||||
|
||||
``solidity-upgrade`` is not considered to be complete or free from bugs, so
|
||||
please use with care.
|
||||
|
||||
How it works
|
||||
~~~~~~~~~~~~
|
||||
|
||||
You can pass (a) Solidity source file(s) to ``solidity-upgrade [files]``. If
|
||||
these make use of ``import`` statement which refer to files outside the
|
||||
current source file's directory, you need to specify directories that
|
||||
are allowed to read and import files from, by passing
|
||||
``--allow-paths [directory]``. You can ignore missing files by passing
|
||||
``--ignore-missing``.
|
||||
|
||||
``solidity-upgrade`` is based on ``libsolidity`` and can parse, compile and
|
||||
analyse your source files, and might find applicable source upgrades in them.
|
||||
|
||||
Source upgrades are considered to be small textual changes to your source code.
|
||||
They are applied to an in-memory representation of the source files
|
||||
given. The corresponding source file is updated by default, but you can pass
|
||||
``--dry-run`` to simulate to whole upgrade process without writing to any file.
|
||||
|
||||
The upgrade process itself has two phases. In the first phase source files are
|
||||
parsed, and since it is not possible to upgrade source code on that level,
|
||||
errors are collected and can be logged by passing ``--verbose``. No source
|
||||
upgrades available at this point.
|
||||
|
||||
In the second phase, all sources are compiled and all activated upgrade analysis
|
||||
modules are run alongside compilation. By default, all available modules are
|
||||
activated. Please read the documentation on
|
||||
:ref:`available modules <upgrade-modules>` for further details.
|
||||
|
||||
|
||||
This can result in compilation errors that may
|
||||
be fixed by source upgrades. If no errors occur, no source upgrades are being
|
||||
reported and you're done.
|
||||
If errors occur and some upgrade module reported a source upgrade, the first
|
||||
reported one gets applied and compilation is triggered again for all given
|
||||
source files. The previous step is repeated as long as source upgrades are
|
||||
reported. If errors still occur, you can log them by passing ``--verbose``.
|
||||
If no errors occur, your contracts are up to date and can be compiled with
|
||||
the latest version of the compiler.
|
||||
|
||||
.. _upgrade-modules:
|
||||
|
||||
Available upgrade modules
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| Module | Version | Description |
|
||||
+=================+=========+==================================================+
|
||||
| ``constructor`` | 0.5.0 | Constructors must now be defined using the |
|
||||
| | | ``constructor`` keyword. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``visibility`` | 0.5.0 | Explicit function visibility is now mandatory, |
|
||||
| | | defaults to ``public``. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``abstract`` | 0.6.0 | The keyword ``abstract`` has to be used if a |
|
||||
| | | contract does not implement all its functions. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``virtual`` | 0.6.0 | Functions without implementation outside an |
|
||||
| | | interface have to be marked ``virtual``. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``override`` | 0.6.0 | When overriding a function or modifier, the new |
|
||||
| | | keyword ``override`` must be used. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
|
||||
Please read :doc:`0.5.0 release notes <050-breaking-changes>` and
|
||||
:doc:`0.6.0 release notes <060-breaking-changes>` for further details.
|
||||
|
||||
Synopsis
|
||||
~~~~~~~~
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Usage: solidity-upgrade [options] contract.sol
|
||||
|
||||
Allowed options:
|
||||
--help Show help message and exit.
|
||||
--version Show version and exit.
|
||||
--allow-paths path(s)
|
||||
Allow a given path for imports. A list of paths can be
|
||||
supplied by separating them with a comma.
|
||||
--ignore-missing Ignore missing files.
|
||||
--modules module(s) Only activate a specific upgrade module. A list of
|
||||
modules can be supplied by separating them with a comma.
|
||||
--dry-run Apply changes in-memory only and don't write to input
|
||||
file.
|
||||
--verbose Print logs, errors and changes. Shortens output of
|
||||
upgrade patches.
|
||||
--unsafe Accept *unsafe* changes.
|
||||
|
||||
|
||||
|
||||
Bug Reports / Feature requests
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you found a bug or if you have a feature request, please
|
||||
`file an issue <https://github.com/ethereum/solidity/issues/new/choose>`_ on Github.
|
||||
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Assume you have the following contracts you want to update declared in ``Source.sol``:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
// This will not compile
|
||||
pragma solidity >0.4.23;
|
||||
|
||||
contract Updateable {
|
||||
function run() public view returns (bool);
|
||||
function update() public;
|
||||
}
|
||||
|
||||
contract Upgradable {
|
||||
function run() public view returns (bool);
|
||||
function upgrade();
|
||||
}
|
||||
|
||||
contract Source is Updateable, Upgradable {
|
||||
function Source() public {}
|
||||
|
||||
function run()
|
||||
public
|
||||
view
|
||||
returns (bool) {}
|
||||
|
||||
function update() {}
|
||||
function upgrade() {}
|
||||
}
|
||||
|
||||
|
||||
Required changes
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
To bring the contracts up to date with the current Solidity version, the
|
||||
following upgrade modules have to be executed: ``constructor``,
|
||||
``visibility``, ``abstract``, ``override`` and ``virtual``. Please read the
|
||||
documentation on :ref:`available modules <upgrade-modules>` for further details.
|
||||
|
||||
Running the upgrade
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In this example, all modules needed to upgrade the contracts above,
|
||||
are available and all of them are activated by default. Therefore you
|
||||
do not need to specify the ``--modules`` option.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ solidity-upgrade Source.sol --dry-run
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Running analysis (and upgrade) on given source files.
|
||||
..............
|
||||
|
||||
After upgrade:
|
||||
|
||||
Found 0 errors.
|
||||
Found 0 upgrades.
|
||||
|
||||
The above performs a dry-ran upgrade on the given file and logs statistics after all.
|
||||
In this case, the upgrade was successful and no further adjustments are needed.
|
||||
|
||||
Finally, you can run the upgrade and also write to the source file.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ solidity-upgrade Source.sol
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Running analysis (and upgrade) on given source files.
|
||||
..............
|
||||
|
||||
After upgrade:
|
||||
|
||||
Found 0 errors.
|
||||
Found 0 upgrades.
|
||||
|
||||
|
||||
Review changes
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The command above applies all changes as shown below. Please review them carefully.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
pragma solidity >0.4.23;
|
||||
|
||||
abstract contract Updateable {
|
||||
function run() public view virtual returns (bool);
|
||||
function update() public virtual;
|
||||
}
|
||||
|
||||
abstract contract Upgradable {
|
||||
function run() public view virtual returns (bool);
|
||||
function upgrade() public virtual;
|
||||
}
|
||||
|
||||
contract Source is Updateable, Upgradable {
|
||||
constructor() public {}
|
||||
|
||||
function run()
|
||||
public
|
||||
view
|
||||
override(Updateable,Upgradable)
|
||||
returns (bool) {}
|
||||
|
||||
function update() public override {}
|
||||
function upgrade() public override {}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ vector<ContractDefinition const*> resolveDirectBaseContracts(ContractDefinition
|
||||
Declaration const* baseDecl =
|
||||
specifier->name().annotation().referencedDeclaration;
|
||||
auto contract = dynamic_cast<ContractDefinition const*>(baseDecl);
|
||||
solAssert(contract, "contract is null");
|
||||
if (contract)
|
||||
resolvedContracts.emplace_back(contract);
|
||||
}
|
||||
|
||||
|
@ -129,6 +129,7 @@ private:
|
||||
class OverrideChecker
|
||||
{
|
||||
public:
|
||||
using OverrideProxyBySignatureMultiSet = std::multiset<OverrideProxy, OverrideProxy::CompareBySignature>;
|
||||
|
||||
/// @param _errorReporter provides the error logging functionality.
|
||||
explicit OverrideChecker(langutil::ErrorReporter& _errorReporter):
|
||||
@ -137,12 +138,17 @@ public:
|
||||
|
||||
void check(ContractDefinition const& _contract);
|
||||
|
||||
private:
|
||||
struct CompareByID
|
||||
{
|
||||
bool operator()(ContractDefinition const* _a, ContractDefinition const* _b) const;
|
||||
};
|
||||
|
||||
/// Returns all functions of bases (including public state variables) that have not yet been overwritten.
|
||||
/// May contain the same function multiple times when used with shared bases.
|
||||
OverrideProxyBySignatureMultiSet const& inheritedFunctions(ContractDefinition const& _contract) const;
|
||||
OverrideProxyBySignatureMultiSet const& inheritedModifiers(ContractDefinition const& _contract) const;
|
||||
|
||||
private:
|
||||
void checkIllegalOverrides(ContractDefinition const& _contract);
|
||||
/// Performs various checks related to @a _overriding overriding @a _super like
|
||||
/// different return type, invalid visibility change, etc.
|
||||
@ -174,15 +180,8 @@ private:
|
||||
/// Resolves an override list of UserDefinedTypeNames to a list of contracts.
|
||||
std::set<ContractDefinition const*, CompareByID> resolveOverrideList(OverrideSpecifier const& _overrides) const;
|
||||
|
||||
using OverrideProxyBySignatureMultiSet = std::multiset<OverrideProxy, OverrideProxy::CompareBySignature>;
|
||||
|
||||
void checkOverrideList(OverrideProxy _item, OverrideProxyBySignatureMultiSet const& _inherited);
|
||||
|
||||
/// Returns all functions of bases (including public state variables) that have not yet been overwritten.
|
||||
/// May contain the same function multiple times when used with shared bases.
|
||||
OverrideProxyBySignatureMultiSet const& inheritedFunctions(ContractDefinition const& _contract) const;
|
||||
OverrideProxyBySignatureMultiSet const& inheritedModifiers(ContractDefinition const& _contract) const;
|
||||
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
|
||||
/// Cache for inheritedFunctions().
|
||||
|
@ -797,7 +797,7 @@ public:
|
||||
{
|
||||
return
|
||||
CallableDeclaration::virtualSemantics() ||
|
||||
annotation().contract->isInterface();
|
||||
(annotation().contract && annotation().contract->isInterface());
|
||||
}
|
||||
private:
|
||||
StateMutability m_stateMutability;
|
||||
|
14
tools/CMakeLists.txt
Normal file
14
tools/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
add_executable(solidity-upgrade
|
||||
solidityUpgrade/main.cpp
|
||||
solidityUpgrade/UpgradeChange.h
|
||||
solidityUpgrade/UpgradeChange.cpp
|
||||
solidityUpgrade/UpgradeSuite.h
|
||||
solidityUpgrade/Upgrade050.cpp
|
||||
solidityUpgrade/Upgrade060.cpp
|
||||
solidityUpgrade/SourceTransform.h
|
||||
solidityUpgrade/SourceUpgrade.cpp
|
||||
)
|
||||
target_link_libraries(solidity-upgrade PRIVATE solidity Boost::boost Boost::program_options Boost::system)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
159
tools/solidityUpgrade/SourceTransform.h
Normal file
159
tools/solidityUpgrade/SourceTransform.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libsolidity/analysis/OverrideChecker.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace solidity::tools
|
||||
{
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
public:
|
||||
static bool isMultilineKeyword(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _keyword
|
||||
)
|
||||
{
|
||||
return regex_search(
|
||||
_location.text(),
|
||||
std::regex{"(\\b" + _keyword + "\\b\\n|\\r|\\r\\n)"}
|
||||
);
|
||||
}
|
||||
|
||||
static bool hasMutabilityKeyword(langutil::SourceLocation const& _location)
|
||||
{
|
||||
return regex_search(
|
||||
_location.text(),
|
||||
std::regex{"(\\b(pure|view|nonpayable|payable)\\b)"}
|
||||
);
|
||||
}
|
||||
|
||||
static bool hasVirtualKeyword(langutil::SourceLocation const& _location)
|
||||
{
|
||||
return regex_search(_location.text(), std::regex{"(\\b(virtual)\\b)"});
|
||||
}
|
||||
|
||||
static bool hasVisibilityKeyword(langutil::SourceLocation const& _location)
|
||||
{
|
||||
return regex_search(_location.text(), std::regex{"\\bpublic\\b"});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper that provides functions which can analyse declarations and
|
||||
* generate source snippets based on the information retrieved.
|
||||
*/
|
||||
class SourceGeneration
|
||||
{
|
||||
public:
|
||||
using CompareFunction = frontend::OverrideChecker::CompareByID;
|
||||
using Contracts = std::set<frontend::ContractDefinition const*, CompareFunction>;
|
||||
|
||||
/// Generates an `override` declaration for single overrides
|
||||
/// or `override(...)` with contract list for multiple overrides.
|
||||
static std::string functionOverride(Contracts const& _contracts)
|
||||
{
|
||||
if (_contracts.size() <= 1)
|
||||
return "override";
|
||||
|
||||
std::string overrideList;
|
||||
for (auto inheritedContract: _contracts)
|
||||
overrideList += inheritedContract->name() + ",";
|
||||
|
||||
return "override(" + overrideList.substr(0, overrideList.size() - 1) + ")";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper that provides functions which apply changes to Solidity source code
|
||||
* on a textual base. In general, these utilize regular expressions applied
|
||||
* to the given source location.
|
||||
*/
|
||||
class SourceTransform
|
||||
{
|
||||
public:
|
||||
/// Searches for the keyword given and prepends the expression.
|
||||
/// E.g. `function f() view;` -> `function f() public view;`
|
||||
static std::string insertBeforeKeyword(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _keyword,
|
||||
std::string const& _expression
|
||||
)
|
||||
{
|
||||
return regex_replace(
|
||||
_location.text(),
|
||||
std::regex{"(\\b" + _keyword + "\\b)"},
|
||||
_expression + " " + _keyword
|
||||
);
|
||||
}
|
||||
|
||||
/// Searches for the keyword given and appends the expression.
|
||||
/// E.g. `function f() public {}` -> `function f() public override {}`
|
||||
static std::string insertAfterKeyword(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _keyword,
|
||||
std::string const& _expression
|
||||
)
|
||||
{
|
||||
bool isMultiline = SourceAnalysis::isMultilineKeyword(_location, _keyword);
|
||||
std::string toAppend = isMultiline ? ("\n " + _expression) : (" " + _expression);
|
||||
std::regex keyword{"(\\b" + _keyword + "\\b)"};
|
||||
|
||||
return regex_replace(_location.text(), keyword, _keyword + toAppend);
|
||||
}
|
||||
|
||||
/// Searches for the first right parenthesis and appends the expression
|
||||
/// given.
|
||||
/// E.g. `function f() {}` -> `function f() public {}`
|
||||
static std::string insertAfterRightParenthesis(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _expression
|
||||
)
|
||||
{
|
||||
return regex_replace(
|
||||
_location.text(),
|
||||
std::regex{"(\\))"},
|
||||
") " + _expression
|
||||
);
|
||||
}
|
||||
|
||||
/// Searches for the `function` keyword and its identifier and replaces
|
||||
/// both by the expression given.
|
||||
/// E.g. `function Storage() {}` -> `constructor() {}`
|
||||
static std::string replaceFunctionName(
|
||||
langutil::SourceLocation const& _location,
|
||||
std::string const& _name,
|
||||
std::string const& _expression
|
||||
)
|
||||
{
|
||||
return regex_replace(
|
||||
_location.text(),
|
||||
std::regex{"(\\bfunction\\s*" + _name + "\\b)"},
|
||||
_expression
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
525
tools/solidityUpgrade/SourceUpgrade.cpp
Normal file
525
tools/solidityUpgrade/SourceUpgrade.cpp
Normal file
@ -0,0 +1,525 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <tools/solidityUpgrade/SourceUpgrade.h>
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <liblangutil/SourceReferenceFormatterHuman.h>
|
||||
|
||||
#include <libsolidity/ast/AST.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
using namespace solidity;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::tools;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::frontend;
|
||||
using namespace std;
|
||||
|
||||
|
||||
static string const g_argHelp = "help";
|
||||
static string const g_argVersion = "version";
|
||||
static string const g_argInputFile = "input-file";
|
||||
static string const g_argModules = "modules";
|
||||
static string const g_argDryRun = "dry-run";
|
||||
static string const g_argUnsafe = "unsafe";
|
||||
static string const g_argVerbose = "verbose";
|
||||
static string const g_argIgnoreMissingFiles = "ignore-missing";
|
||||
static string const g_argAllowPaths = "allow-paths";
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
ostream& out()
|
||||
{
|
||||
return cout;
|
||||
}
|
||||
|
||||
AnsiColorized log()
|
||||
{
|
||||
return AnsiColorized(cout, true, {});
|
||||
}
|
||||
|
||||
AnsiColorized success()
|
||||
{
|
||||
return AnsiColorized(cout, true, {formatting::CYAN});
|
||||
}
|
||||
|
||||
AnsiColorized warning()
|
||||
{
|
||||
return AnsiColorized(cout, true, {formatting::YELLOW});
|
||||
}
|
||||
|
||||
AnsiColorized error()
|
||||
{
|
||||
return AnsiColorized(cout, true, {formatting::MAGENTA});
|
||||
}
|
||||
|
||||
void logVersion()
|
||||
{
|
||||
/// TODO Replace by variable that can be set during build.
|
||||
out() << "0.1.0" << endl;
|
||||
}
|
||||
|
||||
void logProgress()
|
||||
{
|
||||
out() << ".";
|
||||
out().flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SourceUpgrade::parseArguments(int _argc, char** _argv)
|
||||
{
|
||||
po::options_description desc(R"(solidity-upgrade, the Solidity upgrade assistant.
|
||||
|
||||
The solidity-upgrade tool can help upgrade smart contracts to breaking language features.
|
||||
|
||||
It does not support all breaking changes for each version, but will hopefully assist
|
||||
upgrading your contracts to the desired Solidity version.
|
||||
|
||||
solidity-upgrade is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY. Please be careful when running upgrades on
|
||||
your contracts.
|
||||
|
||||
Usage: solidity-upgrade [options] contract.sol
|
||||
|
||||
Allowed options)",
|
||||
po::options_description::m_default_line_length,
|
||||
po::options_description::m_default_line_length - 23
|
||||
);
|
||||
desc.add_options()
|
||||
(g_argHelp.c_str(), "Show help message and exit.")
|
||||
(g_argVersion.c_str(), "Show version and exit.")
|
||||
(
|
||||
g_argAllowPaths.c_str(),
|
||||
po::value<string>()->value_name("path(s)"),
|
||||
"Allow a given path for imports. A list of paths can be supplied by separating them "
|
||||
"with a comma."
|
||||
)
|
||||
(g_argIgnoreMissingFiles.c_str(), "Ignore missing files.")
|
||||
(
|
||||
g_argModules.c_str(),
|
||||
po::value<string>()->value_name("module(s)"),
|
||||
"Only activate a specific upgrade module. A list of "
|
||||
"modules can be supplied by separating them with a comma."
|
||||
)
|
||||
(g_argDryRun.c_str(), "Apply changes in-memory only and don't write to input file.")
|
||||
(g_argVerbose.c_str(), "Print logs, errors and changes. Shortens output of upgrade patches.")
|
||||
(g_argUnsafe.c_str(), "Accept *unsafe* changes.");
|
||||
|
||||
|
||||
po::options_description allOptions = desc;
|
||||
allOptions.add_options()("input-file", po::value<vector<string>>(), "input file");
|
||||
|
||||
po::positional_options_description filesPositions;
|
||||
filesPositions.add("input-file", -1);
|
||||
|
||||
// parse the compiler arguments
|
||||
try
|
||||
{
|
||||
po::command_line_parser cmdLineParser(_argc, _argv);
|
||||
cmdLineParser.style(
|
||||
po::command_line_style::default_style & (~po::command_line_style::allow_guessing)
|
||||
);
|
||||
cmdLineParser.options(allOptions).positional(filesPositions);
|
||||
po::store(cmdLineParser.run(), m_args);
|
||||
}
|
||||
catch (po::error const& _exception)
|
||||
{
|
||||
error() << _exception.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1))
|
||||
{
|
||||
out() << endl;
|
||||
log() << desc;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argVersion))
|
||||
{
|
||||
logVersion();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argModules))
|
||||
{
|
||||
vector<string> moduleArgs;
|
||||
auto modules = boost::split(
|
||||
moduleArgs, m_args[g_argModules].as<string>(), boost::is_any_of(",")
|
||||
);
|
||||
|
||||
/// All modules are activated by default. Clear them before activating single ones.
|
||||
m_suite.deactivateModules();
|
||||
|
||||
for (string const& module: modules)
|
||||
{
|
||||
if (module == "constructor")
|
||||
m_suite.activateModule(Module::ConstructorKeyword);
|
||||
else if (module == "visibility")
|
||||
m_suite.activateModule(Module::VisibilitySpecifier);
|
||||
else if (module == "abstract")
|
||||
m_suite.activateModule(Module::AbstractContract);
|
||||
else if (module == "override")
|
||||
m_suite.activateModule(Module::OverridingFunction);
|
||||
else if (module == "virtual")
|
||||
m_suite.activateModule(Module::VirtualFunction);
|
||||
else
|
||||
{
|
||||
error() << "Unknown upgrade module \"" + module + "\"" << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO Share with solc commandline interface.
|
||||
if (m_args.count(g_argAllowPaths))
|
||||
{
|
||||
vector<string> paths;
|
||||
auto allowedPaths = boost::split(
|
||||
paths, m_args[g_argAllowPaths].as<string>(), boost::is_any_of(",")
|
||||
);
|
||||
for (string const& path: allowedPaths)
|
||||
{
|
||||
auto filesystem_path = boost::filesystem::path(path);
|
||||
/// If the given path had a trailing slash, the Boost filesystem
|
||||
/// path will have it's last component set to '.'. This breaks
|
||||
/// path comparison in later parts of the code, so we need to strip
|
||||
/// it.
|
||||
if (filesystem_path.filename() == ".")
|
||||
filesystem_path.remove_filename();
|
||||
m_allowedDirectories.push_back(filesystem_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SourceUpgrade::printPrologue()
|
||||
{
|
||||
out() << endl;
|
||||
out() << endl;
|
||||
|
||||
log() <<
|
||||
"solidity-upgrade does not support all breaking changes for each version." <<
|
||||
endl <<
|
||||
"Please run `solidity-upgrade --help` and get a list of implemented upgrades." <<
|
||||
endl <<
|
||||
endl;
|
||||
|
||||
log() <<
|
||||
"Running analysis (and upgrade) on given source files." <<
|
||||
endl;
|
||||
}
|
||||
|
||||
bool SourceUpgrade::processInput()
|
||||
{
|
||||
if (!readInputFiles())
|
||||
return false;
|
||||
|
||||
resetCompiler(fileReader());
|
||||
|
||||
tryCompile();
|
||||
runUpgrade();
|
||||
|
||||
printStatistics();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SourceUpgrade::tryCompile() const
|
||||
{
|
||||
bool verbose = m_args.count(g_argVerbose);
|
||||
|
||||
if (verbose)
|
||||
log() << "Running compilation phases." << endl << endl;
|
||||
else
|
||||
logProgress();
|
||||
|
||||
try
|
||||
{
|
||||
if (m_compiler->parse())
|
||||
{
|
||||
if (m_compiler->analyze())
|
||||
m_compiler->compile();
|
||||
else
|
||||
if (verbose)
|
||||
{
|
||||
error() <<
|
||||
"Compilation errors that solidity-upgrade may resolve occurred." <<
|
||||
endl <<
|
||||
endl;
|
||||
|
||||
printErrors();
|
||||
}
|
||||
}
|
||||
else
|
||||
if (verbose)
|
||||
{
|
||||
error() <<
|
||||
"Compilation errors that solidity-upgrade cannot resolve occurred." <<
|
||||
endl <<
|
||||
endl;
|
||||
|
||||
printErrors();
|
||||
}
|
||||
}
|
||||
catch (Exception const& _exception)
|
||||
{
|
||||
error() << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl;
|
||||
}
|
||||
catch (std::exception const& _e)
|
||||
{
|
||||
error() << (_e.what() ? ": " + string(_e.what()) : ".") << endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error() << "Unknown exception during compilation." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SourceUpgrade::runUpgrade()
|
||||
{
|
||||
bool recompile = true;
|
||||
|
||||
while (recompile && !m_compiler->errors().empty())
|
||||
{
|
||||
for (auto& sourceCode: m_sourceCodes)
|
||||
{
|
||||
recompile = analyzeAndUpgrade(sourceCode);
|
||||
if (recompile)
|
||||
break;
|
||||
}
|
||||
|
||||
if (recompile)
|
||||
{
|
||||
m_suite.reset();
|
||||
resetCompiler();
|
||||
tryCompile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SourceUpgrade::analyzeAndUpgrade(pair<string, string> const& _sourceCode)
|
||||
{
|
||||
bool applyUnsafe = m_args.count(g_argUnsafe);
|
||||
bool verbose = m_args.count(g_argVerbose);
|
||||
|
||||
if (verbose)
|
||||
log() << "Analyzing and upgrading " << _sourceCode.first << "." << endl;
|
||||
|
||||
if (m_compiler->state() >= CompilerStack::State::AnalysisPerformed)
|
||||
m_suite.analyze(m_compiler->ast(_sourceCode.first));
|
||||
|
||||
if (!m_suite.changes().empty())
|
||||
{
|
||||
auto& change = m_suite.changes().front();
|
||||
|
||||
if (verbose)
|
||||
change.log(true);
|
||||
|
||||
if (change.level() == UpgradeChange::Level::Safe)
|
||||
{
|
||||
applyChange(_sourceCode, change);
|
||||
return true;
|
||||
}
|
||||
else if (change.level() == UpgradeChange::Level::Unsafe)
|
||||
{
|
||||
if (applyUnsafe)
|
||||
{
|
||||
applyChange(_sourceCode, change);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SourceUpgrade::applyChange(
|
||||
pair<string, string> const& _sourceCode,
|
||||
UpgradeChange& _change
|
||||
)
|
||||
{
|
||||
bool dryRun = m_args.count(g_argDryRun);
|
||||
bool verbose = m_args.count(g_argVerbose);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
log() << "Applying change to " << _sourceCode.first << endl << endl;
|
||||
log() << _change.patch();
|
||||
}
|
||||
|
||||
_change.apply();
|
||||
m_sourceCodes[_sourceCode.first] = _change.source();
|
||||
|
||||
if (!dryRun)
|
||||
writeInputFile(_sourceCode.first, _change.source());
|
||||
}
|
||||
|
||||
void SourceUpgrade::printErrors() const
|
||||
{
|
||||
auto formatter = make_unique<langutil::SourceReferenceFormatterHuman>(cout, true);
|
||||
|
||||
for (auto const& error: m_compiler->errors())
|
||||
if (error->type() != langutil::Error::Type::Warning)
|
||||
formatter->printErrorInformation(*error);
|
||||
}
|
||||
|
||||
void SourceUpgrade::printStatistics() const
|
||||
{
|
||||
out() << endl;
|
||||
out() << endl;
|
||||
out() << "After upgrade:" << endl;
|
||||
out() << endl;
|
||||
error() << "Found " << m_compiler->errors().size() << " errors." << endl;
|
||||
success() << "Found " << m_suite.changes().size() << " upgrades." << endl;
|
||||
}
|
||||
|
||||
bool SourceUpgrade::readInputFiles()
|
||||
{
|
||||
bool ignoreMissing = m_args.count(g_argIgnoreMissingFiles);
|
||||
|
||||
/// TODO Share with solc commandline interface.
|
||||
if (m_args.count(g_argInputFile))
|
||||
for (string path: m_args[g_argInputFile].as<vector<string>>())
|
||||
{
|
||||
auto infile = boost::filesystem::path(path);
|
||||
if (!boost::filesystem::exists(infile))
|
||||
{
|
||||
if (!ignoreMissing)
|
||||
{
|
||||
error() << infile << " is not found." << endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
error() << infile << " is not found. Skipping." << endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!boost::filesystem::is_regular_file(infile))
|
||||
{
|
||||
if (!ignoreMissing)
|
||||
{
|
||||
error() << infile << " is not a valid file." << endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
error() << infile << " is not a valid file. Skipping." << endl;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
m_sourceCodes[infile.generic_string()] = readFileAsString(infile.string());
|
||||
path = boost::filesystem::canonical(infile).string();
|
||||
}
|
||||
|
||||
if (m_sourceCodes.size() == 0)
|
||||
{
|
||||
warning() << "No input files given. If you wish to use the standard input please specify \"-\" explicitly." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SourceUpgrade::writeInputFile(string const& _path, string const& _source)
|
||||
{
|
||||
bool verbose = m_args.count(g_argVerbose);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
out() << endl;
|
||||
log() << "Writing to input file " << _path << "." << endl;
|
||||
}
|
||||
|
||||
ofstream file(_path, ios::trunc);
|
||||
file << _source;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ReadCallback::Callback SourceUpgrade::fileReader()
|
||||
{
|
||||
/// TODO Share with solc commandline interface.
|
||||
ReadCallback::Callback fileReader = [this](string const&, string const& _path)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto path = boost::filesystem::path(_path);
|
||||
auto canonicalPath = boost::filesystem::weakly_canonical(path);
|
||||
bool isAllowed = false;
|
||||
for (auto const& allowedDir: m_allowedDirectories)
|
||||
{
|
||||
// If dir is a prefix of boostPath, we are fine.
|
||||
if (
|
||||
std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) &&
|
||||
std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin())
|
||||
)
|
||||
{
|
||||
isAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isAllowed)
|
||||
return ReadCallback::Result{false, "File outside of allowed directories."};
|
||||
|
||||
if (!boost::filesystem::exists(canonicalPath))
|
||||
return ReadCallback::Result{false, "File not found."};
|
||||
|
||||
if (!boost::filesystem::is_regular_file(canonicalPath))
|
||||
return ReadCallback::Result{false, "Not a valid file."};
|
||||
|
||||
auto contents = readFileAsString(canonicalPath.string());
|
||||
m_sourceCodes[path.generic_string()] = contents;
|
||||
return ReadCallback::Result{true, contents};
|
||||
}
|
||||
catch (Exception const& _exception)
|
||||
{
|
||||
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return ReadCallback::Result{false, "Unknown exception in read callback."};
|
||||
}
|
||||
};
|
||||
|
||||
return fileReader;
|
||||
}
|
||||
|
||||
void SourceUpgrade::resetCompiler()
|
||||
{
|
||||
m_compiler->reset();
|
||||
m_compiler->setSources(m_sourceCodes);
|
||||
m_compiler->setParserErrorRecovery(true);
|
||||
}
|
||||
|
||||
void SourceUpgrade::resetCompiler(ReadCallback::Callback const& _callback)
|
||||
{
|
||||
m_compiler.reset(new CompilerStack(_callback));
|
||||
m_compiler->setSources(m_sourceCodes);
|
||||
m_compiler->setParserErrorRecovery(true);
|
||||
}
|
158
tools/solidityUpgrade/SourceUpgrade.h
Normal file
158
tools/solidityUpgrade/SourceUpgrade.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
||||
#include <tools/solidityUpgrade/Upgrade050.h>
|
||||
#include <tools/solidityUpgrade/Upgrade060.h>
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace solidity::tools
|
||||
{
|
||||
|
||||
/**
|
||||
* The Solidity source upgrade tool. It supplies a command line interface
|
||||
* and connects this to a compiler stack that the upgrade logic is facilitated
|
||||
* with.
|
||||
*/
|
||||
class SourceUpgrade
|
||||
{
|
||||
public:
|
||||
/// Parse command line arguments and return false in case of a failure.
|
||||
bool parseArguments(int _argc, char** _argv);
|
||||
/// Prints additional information on the upgrade tool.
|
||||
void printPrologue();
|
||||
/// Parse / compile files and runs upgrade analysis on them.
|
||||
bool processInput();
|
||||
|
||||
private:
|
||||
/// All available upgrade modules
|
||||
enum class Module
|
||||
{
|
||||
ConstructorKeyword,
|
||||
VisibilitySpecifier,
|
||||
AbstractContract,
|
||||
OverridingFunction,
|
||||
VirtualFunction
|
||||
};
|
||||
|
||||
/// Upgrade suite that hosts all available modules.
|
||||
class Suite: public UpgradeSuite
|
||||
{
|
||||
public:
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit)
|
||||
{
|
||||
/// Solidity 0.5.0
|
||||
if (isActivated(Module::ConstructorKeyword))
|
||||
ConstructorKeyword{m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::VisibilitySpecifier))
|
||||
VisibilitySpecifier{m_changes}.analyze(_sourceUnit);
|
||||
|
||||
/// Solidity 0.6.0
|
||||
if (isActivated(Module::AbstractContract))
|
||||
AbstractContract{m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::OverridingFunction))
|
||||
OverridingFunction{m_changes}.analyze(_sourceUnit);
|
||||
if (isActivated(Module::VirtualFunction))
|
||||
VirtualFunction{m_changes}.analyze(_sourceUnit);
|
||||
}
|
||||
|
||||
void activateModule(Module _module) { m_modules.insert(_module); }
|
||||
void deactivateModules() { m_modules.clear(); }
|
||||
|
||||
private:
|
||||
bool isActivated(Module _module) const
|
||||
{
|
||||
return m_modules.find(_module) != m_modules.end();
|
||||
}
|
||||
|
||||
/// All modules are activated by default. Clear them before activating
|
||||
/// single ones.
|
||||
std::set<Module> m_modules = {
|
||||
Module::ConstructorKeyword,
|
||||
Module::VisibilitySpecifier,
|
||||
Module::AbstractContract,
|
||||
Module::OverridingFunction,
|
||||
Module::VirtualFunction
|
||||
};
|
||||
};
|
||||
|
||||
/// Parses the current sources and runs analyses as well as compilation on
|
||||
/// them if parsing was successful.
|
||||
void tryCompile() const;
|
||||
/// Analyses and upgrades the sources given. The upgrade happens in a loop,
|
||||
/// applying one change at a time, which is run until no applicable changes
|
||||
/// are found any more. Only one change is done at a time and all sources
|
||||
/// are being compiled again after each change.
|
||||
void runUpgrade();
|
||||
/// Runs upgrade analysis on source and applies upgrades changes to it.
|
||||
/// Returns `true` if there're still changes that can be applied,
|
||||
/// `false` otherwise.
|
||||
bool analyzeAndUpgrade(
|
||||
std::pair<std::string, std::string> const& _sourceCode
|
||||
);
|
||||
|
||||
/// Applies the change given to its source code. If no `--dry-run` was
|
||||
/// passed via the commandline, the upgraded source code is written back
|
||||
/// to its file.
|
||||
void applyChange(
|
||||
std::pair<std::string, std::string> const& _sourceCode,
|
||||
UpgradeChange& _change
|
||||
);
|
||||
|
||||
/// Prints all errors (excluding warnings) the compiler currently reported.
|
||||
void printErrors() const;
|
||||
/// Prints error and upgrade overview at the end of each full run.
|
||||
void printStatistics() const;
|
||||
|
||||
/// Reads all input files given and stores sources in the internal data
|
||||
/// structure. Reports errors if files cannot be found.
|
||||
bool readInputFiles();
|
||||
/// Writes source to file given.
|
||||
bool writeInputFile(std::string const& _path, std::string const& _source);
|
||||
/// Returns a file reader function that fills `m_sources`.
|
||||
frontend::ReadCallback::Callback fileReader();
|
||||
|
||||
/// Resets the compiler stack and configures sources to compile.
|
||||
/// Also enables error recovery.
|
||||
void resetCompiler();
|
||||
/// Resets the compiler stack and configures sources to compile.
|
||||
/// Also enables error recovery. Passes read callback to the compiler stack.
|
||||
void resetCompiler(frontend::ReadCallback::Callback const& _callback);
|
||||
|
||||
/// Compiler arguments variable map
|
||||
boost::program_options::variables_map m_args;
|
||||
/// Map of input files to source code strings
|
||||
std::map<std::string, std::string> m_sourceCodes;
|
||||
/// Solidity compiler stack
|
||||
std::unique_ptr<frontend::CompilerStack> m_compiler;
|
||||
/// List of allowed directories to read files from
|
||||
std::vector<boost::filesystem::path> m_allowedDirectories;
|
||||
/// Holds all upgrade modules and source upgrades.
|
||||
Suite m_suite;
|
||||
};
|
||||
|
||||
}
|
58
tools/solidityUpgrade/Upgrade050.cpp
Normal file
58
tools/solidityUpgrade/Upgrade050.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <tools/solidityUpgrade/Upgrade050.h>
|
||||
#include <tools/solidityUpgrade/SourceTransform.h>
|
||||
|
||||
#include <libsolidity/analysis/OverrideChecker.h>
|
||||
|
||||
#include <libyul/AsmData.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::tools;
|
||||
|
||||
void ConstructorKeyword::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
for (auto const* function: _contract.definedFunctions())
|
||||
if (function->name() == _contract.name())
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
SourceTransform::replaceFunctionName(
|
||||
function->location(),
|
||||
function->name(),
|
||||
"constructor"
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void VisibilitySpecifier::endVisit(FunctionDefinition const& _function)
|
||||
{
|
||||
if (_function.noVisibilitySpecified())
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
_function.location(),
|
||||
SourceTransform::insertAfterRightParenthesis(_function.location(), "public")
|
||||
}
|
||||
);
|
||||
}
|
58
tools/solidityUpgrade/Upgrade050.h
Normal file
58
tools/solidityUpgrade/Upgrade050.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
||||
#include <tools/solidityUpgrade/UpgradeSuite.h>
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
|
||||
namespace solidity::tools
|
||||
{
|
||||
|
||||
/**
|
||||
* Module that performs analysis on the AST. It visits all contract
|
||||
* definitions and its defined functions and reports a source upgrade,
|
||||
* if one of the declared functions is the constructor but does not
|
||||
* use the `constructor` keyword.
|
||||
*/
|
||||
class ConstructorKeyword: public AnalysisUpgrade
|
||||
{
|
||||
public:
|
||||
using AnalysisUpgrade::AnalysisUpgrade;
|
||||
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
void endVisit(frontend::ContractDefinition const& _contract);
|
||||
};
|
||||
|
||||
/**
|
||||
* Module that performs analysis on the AST. It visits function definitions
|
||||
* and reports a source upgrade, if this function's visibility is `public`,
|
||||
* but not marked explicitly as such.
|
||||
*/
|
||||
class VisibilitySpecifier: public AnalysisUpgrade
|
||||
{
|
||||
public:
|
||||
using AnalysisUpgrade::AnalysisUpgrade;
|
||||
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
void endVisit(frontend::FunctionDefinition const& _function);
|
||||
};
|
||||
|
||||
}
|
212
tools/solidityUpgrade/Upgrade060.cpp
Normal file
212
tools/solidityUpgrade/Upgrade060.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <tools/solidityUpgrade/Upgrade060.h>
|
||||
#include <tools/solidityUpgrade/SourceTransform.h>
|
||||
|
||||
#include <libsolidity/analysis/OverrideChecker.h>
|
||||
|
||||
#include <libyul/AsmData.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::frontend;
|
||||
using namespace solidity::tools;
|
||||
|
||||
using Contracts = set<ContractDefinition const*, OverrideChecker::CompareByID>;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline string appendOverride(
|
||||
FunctionDefinition const& _function,
|
||||
Contracts const& _expectedContracts
|
||||
)
|
||||
{
|
||||
auto location = _function.location();
|
||||
string upgradedCode;
|
||||
string overrideExpression = SourceGeneration::functionOverride(_expectedContracts);
|
||||
|
||||
if (SourceAnalysis::hasVirtualKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
"virtual",
|
||||
overrideExpression
|
||||
);
|
||||
else if (SourceAnalysis::hasMutabilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
stateMutabilityToString(_function.stateMutability()),
|
||||
overrideExpression
|
||||
);
|
||||
else if (SourceAnalysis::hasVisibilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
Declaration::visibilityToString(_function.visibility()),
|
||||
overrideExpression
|
||||
);
|
||||
else
|
||||
upgradedCode = SourceTransform::insertAfterRightParenthesis(
|
||||
location,
|
||||
overrideExpression
|
||||
);
|
||||
|
||||
return upgradedCode;
|
||||
}
|
||||
|
||||
inline string appendVirtual(FunctionDefinition const& _function)
|
||||
{
|
||||
auto location = _function.location();
|
||||
string upgradedCode;
|
||||
|
||||
if (SourceAnalysis::hasMutabilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
stateMutabilityToString(_function.stateMutability()),
|
||||
"virtual"
|
||||
);
|
||||
else if (SourceAnalysis::hasVisibilityKeyword(location))
|
||||
upgradedCode = SourceTransform::insertAfterKeyword(
|
||||
location,
|
||||
Declaration::visibilityToString(_function.visibility()),
|
||||
"virtual"
|
||||
);
|
||||
else
|
||||
upgradedCode = SourceTransform::insertAfterRightParenthesis(
|
||||
_function.location(),
|
||||
"virtual"
|
||||
);
|
||||
|
||||
return upgradedCode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AbstractContract::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
bool isFullyImplemented = _contract.annotation().unimplementedFunctions.empty();
|
||||
|
||||
if (
|
||||
!isFullyImplemented &&
|
||||
!_contract.abstract() &&
|
||||
!_contract.isInterface()
|
||||
)
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
_contract.location(),
|
||||
SourceTransform::insertBeforeKeyword(_contract.location(), "contract", "abstract")
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void OverridingFunction::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
auto const& inheritedFunctions = m_overrideChecker.inheritedFunctions(_contract);
|
||||
|
||||
for (auto const* function: _contract.definedFunctions())
|
||||
{
|
||||
Contracts expectedContracts;
|
||||
OverrideProxy proxy{function};
|
||||
|
||||
if (!function->isConstructor())
|
||||
{
|
||||
/// Build list of contracts expected to be mentioned in the override list (if any).
|
||||
for (auto [begin, end] = inheritedFunctions.equal_range(proxy); begin != end; begin++)
|
||||
expectedContracts.insert(&begin->contract());
|
||||
|
||||
/// Add override with contract list, if needed.
|
||||
if (!function->overrides() && expectedContracts.size() > 1)
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
appendOverride(*function, expectedContracts)
|
||||
}
|
||||
);
|
||||
|
||||
for (auto [begin, end] = inheritedFunctions.equal_range(proxy); begin != end; begin++)
|
||||
{
|
||||
auto& super = (*begin);
|
||||
auto functionType = FunctionType(*function).asCallableFunction(false);
|
||||
auto superType = super.functionType()->asCallableFunction(false);
|
||||
|
||||
if (functionType && functionType->hasEqualParameterTypes(*superType))
|
||||
{
|
||||
/// If function does not specify override and no override with
|
||||
/// contract list was added before.
|
||||
if (!function->overrides() && expectedContracts.size() <= 1)
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
appendOverride(*function, expectedContracts)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualFunction::endVisit(ContractDefinition const& _contract)
|
||||
{
|
||||
auto const& inheritedFunctions = m_overrideChecker.inheritedFunctions(_contract);
|
||||
|
||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||
{
|
||||
OverrideProxy proxy{function};
|
||||
|
||||
if (!function->isConstructor())
|
||||
{
|
||||
if (
|
||||
!function->markedVirtual() &&
|
||||
!function->isImplemented() &&
|
||||
!function->virtualSemantics() &&
|
||||
function->visibility() > Visibility::Private
|
||||
)
|
||||
{
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
appendVirtual(*function)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for (auto [begin, end] = inheritedFunctions.equal_range(proxy); begin != end; begin++)
|
||||
{
|
||||
auto& super = (*begin);
|
||||
if (
|
||||
!function->markedVirtual() &&
|
||||
!super.virtualSemantics()
|
||||
)
|
||||
{
|
||||
m_changes.push_back(
|
||||
UpgradeChange{
|
||||
UpgradeChange::Level::Safe,
|
||||
function->location(),
|
||||
appendVirtual(*function)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
tools/solidityUpgrade/Upgrade060.h
Normal file
69
tools/solidityUpgrade/Upgrade060.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
||||
#include <tools/solidityUpgrade/UpgradeSuite.h>
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
|
||||
namespace solidity::tools
|
||||
{
|
||||
|
||||
/**
|
||||
* Module that performs analysis on the AST. Finds abstract contracts that are
|
||||
* not marked as such and adds the `abstract` keyword.
|
||||
*/
|
||||
class AbstractContract: public AnalysisUpgrade
|
||||
{
|
||||
public:
|
||||
using AnalysisUpgrade::AnalysisUpgrade;
|
||||
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
void endVisit(frontend::ContractDefinition const& _contract);
|
||||
};
|
||||
|
||||
/**
|
||||
* Module that performs analysis on the AST. Finds functions that need to be
|
||||
* marked `override` and adds the keyword to the function header.
|
||||
*/
|
||||
class OverridingFunction: public AnalysisUpgrade
|
||||
{
|
||||
public:
|
||||
using AnalysisUpgrade::AnalysisUpgrade;
|
||||
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
void endVisit(frontend::ContractDefinition const& _contract);
|
||||
};
|
||||
|
||||
/**
|
||||
* Module that performs analysis on the AST. Finds functions that need to be
|
||||
* marked `virtual` and adds the keyword to the function header.
|
||||
*/
|
||||
class VirtualFunction: public AnalysisUpgrade
|
||||
{
|
||||
public:
|
||||
using AnalysisUpgrade::AnalysisUpgrade;
|
||||
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
||||
private:
|
||||
void endVisit(frontend::ContractDefinition const& _function);
|
||||
};
|
||||
|
||||
}
|
73
tools/solidityUpgrade/UpgradeChange.cpp
Normal file
73
tools/solidityUpgrade/UpgradeChange.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
||||
|
||||
#include <liblangutil/SourceReferenceExtractor.h>
|
||||
#include <liblangutil/SourceReferenceFormatterHuman.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::util;
|
||||
using namespace solidity::tools;
|
||||
|
||||
void UpgradeChange::apply()
|
||||
{
|
||||
m_source.replace(m_location.start, m_location.end - m_location.start, m_patch);
|
||||
}
|
||||
|
||||
void UpgradeChange::log(bool const _shorten) const
|
||||
{
|
||||
stringstream os;
|
||||
SourceReferenceFormatterHuman formatter{os, true};
|
||||
|
||||
string start = to_string(m_location.start);
|
||||
string end = to_string(m_location.end);
|
||||
|
||||
auto color = m_level == Level::Unsafe ? formatting::MAGENTA : formatting::CYAN;
|
||||
auto level = m_level == Level::Unsafe ? "unsafe" : "safe";
|
||||
|
||||
os << endl;
|
||||
AnsiColorized(os, true, {formatting::BOLD, color}) << "Upgrade change (" << level << ")" << endl;
|
||||
os << "=======================" << endl;
|
||||
formatter.printSourceLocation(SourceReferenceExtractor::extract(&m_location));
|
||||
os << endl;
|
||||
|
||||
LineColumn lineEnd = m_location.source->translatePositionToLineColumn(m_location.end);
|
||||
int const leftpad = static_cast<int>(log10(max(lineEnd.line, 1))) + 2;
|
||||
|
||||
stringstream output;
|
||||
output << (_shorten ? shortenSource(m_patch) : m_patch);
|
||||
|
||||
string line;
|
||||
while (getline(output, line))
|
||||
{
|
||||
os << string(leftpad, ' ');
|
||||
AnsiColorized(os, true, {formatting::BOLD, formatting::BLUE}) << "| ";
|
||||
AnsiColorized(os, true, {}) << line << endl;
|
||||
}
|
||||
cout << os.str();
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
string UpgradeChange::shortenSource(string const& _source)
|
||||
{
|
||||
size_t constexpr maxSourceLength = 1000;
|
||||
if (_source.size() > maxSourceLength)
|
||||
return _source.substr(0, min(_source.size(), maxSourceLength)) + "...";
|
||||
return _source;
|
||||
}
|
82
tools/solidityUpgrade/UpgradeChange.h
Normal file
82
tools/solidityUpgrade/UpgradeChange.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
#include <liblangutil/SourceLocation.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace solidity::tools
|
||||
{
|
||||
|
||||
/**
|
||||
* Models a single source code change, based on the initial source location
|
||||
* and a patch, which needs to be applied.
|
||||
* It implements the concept of level of confidence in the change and distiguishes
|
||||
* safe from unsafe changes. A "safe" change is considered to not break
|
||||
* compilation or change semantics. An "unsafe" change is considered to potentially
|
||||
* change semantics or require further manual management.
|
||||
*/
|
||||
class UpgradeChange
|
||||
{
|
||||
public:
|
||||
enum class Level
|
||||
{
|
||||
Safe,
|
||||
Unsafe
|
||||
};
|
||||
|
||||
UpgradeChange(
|
||||
Level _level,
|
||||
langutil::SourceLocation _location,
|
||||
std::string _patch
|
||||
)
|
||||
:
|
||||
m_location(_location),
|
||||
m_source(_location.source->source()),
|
||||
m_patch(_patch),
|
||||
m_level(_level) {}
|
||||
|
||||
~UpgradeChange() {}
|
||||
|
||||
langutil::SourceLocation const& location() { return m_location; }
|
||||
std::string source() const { return m_source; }
|
||||
std::string patch() { return m_patch; }
|
||||
Level level() const { return m_level; }
|
||||
|
||||
/// Does the actual replacement of code under at current source location.
|
||||
/// The change is applied on the upgrade-specific copy of source code.
|
||||
/// The altered code is then requested by the upgrade routine later on.
|
||||
void apply();
|
||||
/// Does a pretty-print of this upgrade change. It uses a source formatter
|
||||
/// provided by the compiler in order to print affected code. Since the patch
|
||||
/// can contain a lot of code lines, it can be shortened, which is signaled
|
||||
/// by setting the flag.
|
||||
void log(bool const _shorten = true) const;
|
||||
private:
|
||||
langutil::SourceLocation m_location;
|
||||
std::string m_source;
|
||||
std::string m_patch;
|
||||
Level m_level;
|
||||
|
||||
/// Shortens the given source to a constant limit.
|
||||
static std::string shortenSource(std::string const& _source);
|
||||
};
|
||||
|
||||
}
|
90
tools/solidityUpgrade/UpgradeSuite.h
Normal file
90
tools/solidityUpgrade/UpgradeSuite.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
||||
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
|
||||
#include <libsolidity/ast/ASTVisitor.h>
|
||||
#include <libsolidity/analysis/OverrideChecker.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace solidity::tools
|
||||
{
|
||||
|
||||
/**
|
||||
* The base upgrade module that can be inherited from. Doing so
|
||||
* creates a basic upgrade module that facilitates access to
|
||||
* change reporting.
|
||||
*/
|
||||
class Upgrade
|
||||
{
|
||||
public:
|
||||
Upgrade(std::vector<UpgradeChange>& _changes): m_changes(_changes) {}
|
||||
|
||||
protected:
|
||||
/// A reference to a suite-specific set of changes.
|
||||
/// It is passed to all upgrade modules and meant to collect
|
||||
/// reported changes.
|
||||
std::vector<UpgradeChange>& m_changes;
|
||||
};
|
||||
|
||||
/**
|
||||
* A specific upgrade module meant to be run after the analysis phase
|
||||
* of the compiler.
|
||||
*/
|
||||
class AnalysisUpgrade: public Upgrade, public frontend::ASTConstVisitor
|
||||
{
|
||||
public:
|
||||
AnalysisUpgrade(std::vector<UpgradeChange>& _changes):
|
||||
Upgrade(_changes),
|
||||
m_errorReporter(m_errors),
|
||||
m_overrideChecker(m_errorReporter)
|
||||
{}
|
||||
/// Interface function for all upgrade modules that are meant
|
||||
/// be run after the analysis phase of the compiler.
|
||||
void analyze(frontend::SourceUnit const&) {}
|
||||
protected:
|
||||
langutil::ErrorList m_errors;
|
||||
langutil::ErrorReporter m_errorReporter;
|
||||
frontend::OverrideChecker m_overrideChecker;
|
||||
};
|
||||
|
||||
/**
|
||||
* The generic upgrade suite. Should be inherited from for each set of
|
||||
* desired upgrade modules.
|
||||
*/
|
||||
class UpgradeSuite
|
||||
{
|
||||
public:
|
||||
/// The base interface function that needs to be implemented for each
|
||||
/// suite. It should create suite-specific upgrade modules and trigger
|
||||
/// their analysis.
|
||||
void analyze(frontend::SourceUnit const& _sourceUnit);
|
||||
/// Resets all changes collected so far.
|
||||
void reset() { m_changes.clear(); }
|
||||
|
||||
std::vector<UpgradeChange>& changes() { return m_changes; }
|
||||
std::vector<UpgradeChange> const& changes() const { return m_changes; }
|
||||
|
||||
protected:
|
||||
std::vector<UpgradeChange> m_changes;
|
||||
};
|
||||
|
||||
}
|
23
tools/solidityUpgrade/contracts/DocsExamplePass.sol
Normal file
23
tools/solidityUpgrade/contracts/DocsExamplePass.sol
Normal file
@ -0,0 +1,23 @@
|
||||
pragma solidity >0.4.23;
|
||||
|
||||
contract Updateable {
|
||||
function run() public view returns (bool);
|
||||
function update() public;
|
||||
}
|
||||
|
||||
contract Upgradable {
|
||||
function run() public view returns (bool);
|
||||
function upgrade();
|
||||
}
|
||||
|
||||
contract Source is Updateable, Upgradable {
|
||||
function Source() public {}
|
||||
|
||||
function run()
|
||||
public
|
||||
view
|
||||
returns (bool) {}
|
||||
|
||||
function update() {}
|
||||
function upgrade() {}
|
||||
}
|
18
tools/solidityUpgrade/contracts/Test.sol
Normal file
18
tools/solidityUpgrade/contracts/Test.sol
Normal file
@ -0,0 +1,18 @@
|
||||
pragma solidity >0.4.23;
|
||||
|
||||
contract Storage {
|
||||
function Storage() public {}
|
||||
function start();
|
||||
function state() public view returns (bool);
|
||||
function stop() public;
|
||||
}
|
||||
|
||||
contract Observable {
|
||||
function state() public view returns (bool);
|
||||
}
|
||||
|
||||
contract VolatileStorage is Storage, Observable {
|
||||
function start() {}
|
||||
function state() public view returns (bool) {}
|
||||
function stop() {}
|
||||
}
|
21
tools/solidityUpgrade/contracts/TestMultiline.sol
Normal file
21
tools/solidityUpgrade/contracts/TestMultiline.sol
Normal file
@ -0,0 +1,21 @@
|
||||
pragma solidity >0.4.23;
|
||||
|
||||
contract Storage {
|
||||
function Storage() {}
|
||||
function init() public;
|
||||
function idle();
|
||||
function destroy() public view;
|
||||
}
|
||||
|
||||
contract VolatileStorage is Storage {
|
||||
function init()
|
||||
public
|
||||
{}
|
||||
|
||||
function idle() {}
|
||||
|
||||
function destroy()
|
||||
public
|
||||
view
|
||||
{}
|
||||
}
|
15
tools/solidityUpgrade/contracts/TestNonFixable.sol
Normal file
15
tools/solidityUpgrade/contracts/TestNonFixable.sol
Normal file
@ -0,0 +1,15 @@
|
||||
pragma solidity >0.4.23;
|
||||
|
||||
contract Storage {
|
||||
function Storage() {}
|
||||
function init() public;
|
||||
function idle();
|
||||
function destroy() public view;
|
||||
}
|
||||
|
||||
contract VolatileStorage is Storage {
|
||||
uint[] array;
|
||||
function init() public { array.length = 3; }
|
||||
function idle() {}
|
||||
function destroy() public view {}
|
||||
}
|
81
tools/solidityUpgrade/main.cpp
Normal file
81
tools/solidityUpgrade/main.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <tools/solidityUpgrade/SourceUpgrade.h>
|
||||
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libsolutil/AnsiColorized.h>
|
||||
|
||||
//#include <test/Common.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace solidity;
|
||||
using namespace std;
|
||||
namespace po = boost::program_options;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
void setupTerminal()
|
||||
{
|
||||
#if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
// Set output mode to handle virtual terminal (ANSI escape sequences)
|
||||
// ignore any error, as this is just a "nice-to-have"
|
||||
// only windows needs to be taken care of, as other platforms (Linux/OSX) support them natively.
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hOut == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
DWORD dwMode = 0;
|
||||
if (!GetConsoleMode(hOut, &dwMode))
|
||||
return;
|
||||
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(hOut, dwMode))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
setupTerminal();
|
||||
|
||||
tools::SourceUpgrade upgrade;
|
||||
if (!upgrade.parseArguments(argc, argv))
|
||||
return 1;
|
||||
upgrade.printPrologue();
|
||||
if (!upgrade.processInput())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user