mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Remove solidity-upgrade
update config.yaml Update using-the-compiler.rst removed bug reports section added changelog entry removed trailing whitespace removed trailing whitespace
This commit is contained in:
parent
229fcc9fce
commit
df2ea19535
@ -173,11 +173,6 @@ defaults:
|
|||||||
- artifact_solc_windows: &artifact_solc_windows
|
- artifact_solc_windows: &artifact_solc_windows
|
||||||
path: upload/
|
path: upload/
|
||||||
|
|
||||||
# compiled tool executable target
|
|
||||||
- artifact_solidity_upgrade: &artifact_solidity_upgrade
|
|
||||||
path: build/tools/solidity-upgrade
|
|
||||||
destination: solidity-upgrade
|
|
||||||
|
|
||||||
- artifact_yul_phaser: &artifact_yul_phaser
|
- artifact_yul_phaser: &artifact_yul_phaser
|
||||||
path: build/tools/yul-phaser
|
path: build/tools/yul-phaser
|
||||||
destination: yul-phaser
|
destination: yul-phaser
|
||||||
@ -251,7 +246,6 @@ defaults:
|
|||||||
- checkout
|
- checkout
|
||||||
- run: *run_build
|
- run: *run_build
|
||||||
- store_artifacts: *artifacts_solc
|
- store_artifacts: *artifacts_solc
|
||||||
- store_artifacts: *artifact_solidity_upgrade
|
|
||||||
- store_artifacts: *artifact_yul_phaser
|
- store_artifacts: *artifact_yul_phaser
|
||||||
- persist_to_workspace: *artifacts_executables
|
- persist_to_workspace: *artifacts_executables
|
||||||
- gitter_notify_failure_unless_pr
|
- gitter_notify_failure_unless_pr
|
||||||
@ -952,7 +946,6 @@ jobs:
|
|||||||
<<: *steps_install_dependencies_osx
|
<<: *steps_install_dependencies_osx
|
||||||
- run: *run_build
|
- run: *run_build
|
||||||
- store_artifacts: *artifacts_solc
|
- store_artifacts: *artifacts_solc
|
||||||
- store_artifacts: *artifact_solidity_upgrade
|
|
||||||
- store_artifacts: *artifact_yul_phaser
|
- store_artifacts: *artifact_yul_phaser
|
||||||
- persist_to_workspace:
|
- persist_to_workspace:
|
||||||
root: .
|
root: .
|
||||||
|
@ -18,6 +18,7 @@ Compiler Features:
|
|||||||
* SMTChecker: Support Eldarica as a Horn solver for the CHC engine when using the CLI option ``--model-checker-solvers eld``. The binary `eld` must be available in the system.
|
* SMTChecker: Support Eldarica as a Horn solver for the CHC engine when using the CLI option ``--model-checker-solvers eld``. The binary `eld` must be available in the system.
|
||||||
* SMTChecker: Make ``z3`` the default solver for the BMC and CHC engines instead of all solvers.
|
* SMTChecker: Make ``z3`` the default solver for the BMC and CHC engines instead of all solvers.
|
||||||
* Parser: More detailed error messages about invalid version pragmas.
|
* Parser: More detailed error messages about invalid version pragmas.
|
||||||
|
* Removed support for the ``solidity-upgrade`` tool.
|
||||||
|
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
|
@ -630,229 +630,4 @@ Error Types
|
|||||||
12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue.
|
12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue.
|
||||||
13. ``YulException``: Error during Yul Code generation - this should be reported as an issue.
|
13. ``YulException``: Error during Yul Code generation - this should be reported as an issue.
|
||||||
14. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible.
|
14. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible.
|
||||||
15. ``Info``: Information that the compiler thinks the user might find useful, but is not dangerous and does not necessarily need to be addressed.
|
15. ``Info``: Information that the compiler thinks the user might find useful, but is not dangerous and does not necessarily need to be addressed.
|
||||||
|
|
||||||
|
|
||||||
.. _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. |
|
|
||||||
+----------------------------+---------+--------------------------------------------------+
|
|
||||||
| ``dotsyntax`` | 0.7.0 | The following syntax is deprecated: |
|
|
||||||
| | | ``f.gas(...)()``, ``f.value(...)()`` and |
|
|
||||||
| | | ``(new C).value(...)()``. Replace these calls by |
|
|
||||||
| | | ``f{gas: ..., value: ...}()`` and |
|
|
||||||
| | | ``(new C){value: ...}()``. |
|
|
||||||
+----------------------------+---------+--------------------------------------------------+
|
|
||||||
| ``now`` | 0.7.0 | The ``now`` keyword is deprecated. Use |
|
|
||||||
| | | ``block.timestamp`` instead. |
|
|
||||||
+----------------------------+---------+--------------------------------------------------+
|
|
||||||
| ``constructor-visibility`` | 0.7.0 | Removes visibility of constructors. |
|
|
||||||
| | | |
|
|
||||||
+----------------------------+---------+--------------------------------------------------+
|
|
||||||
|
|
||||||
Please read :doc:`0.5.0 release notes <050-breaking-changes>`,
|
|
||||||
:doc:`0.6.0 release notes <060-breaking-changes>`,
|
|
||||||
:doc:`0.7.0 release notes <070-breaking-changes>` and :doc:`0.8.0 release notes <080-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 that you have the following contract in ``Source.sol``:
|
|
||||||
|
|
||||||
.. code-block:: Solidity
|
|
||||||
|
|
||||||
pragma solidity >=0.6.0 <0.6.4;
|
|
||||||
// This will not compile after 0.7.0
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
contract C {
|
|
||||||
// FIXME: remove constructor visibility and make the contract abstract
|
|
||||||
constructor() internal {}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract D {
|
|
||||||
uint time;
|
|
||||||
|
|
||||||
function f() public payable {
|
|
||||||
// FIXME: change now to block.timestamp
|
|
||||||
time = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract E {
|
|
||||||
D d;
|
|
||||||
|
|
||||||
// FIXME: remove constructor visibility
|
|
||||||
constructor() public {}
|
|
||||||
|
|
||||||
function g() public {
|
|
||||||
// FIXME: change .value(5) => {value: 5}
|
|
||||||
d.f.value(5)();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Required Changes
|
|
||||||
^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
The above contract will not compile starting from 0.7.0. To bring the contract up to date with the
|
|
||||||
current Solidity version, the following upgrade modules have to be executed:
|
|
||||||
``constructor-visibility``, ``now`` and ``dotsyntax``. Please read the documentation on
|
|
||||||
:ref:`available modules <upgrade-modules>` for further details.
|
|
||||||
|
|
||||||
|
|
||||||
Running the Upgrade
|
|
||||||
^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
It is recommended to explicitly specify the upgrade modules by using ``--modules`` argument.
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
solidity-upgrade --modules constructor-visibility,now,dotsyntax Source.sol
|
|
||||||
|
|
||||||
The command above applies all changes as shown below. Please review them carefully (the pragmas will
|
|
||||||
have to be updated manually.)
|
|
||||||
|
|
||||||
.. code-block:: Solidity
|
|
||||||
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
pragma solidity >=0.7.0 <0.9.0;
|
|
||||||
abstract contract C {
|
|
||||||
// FIXME: remove constructor visibility and make the contract abstract
|
|
||||||
constructor() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract D {
|
|
||||||
uint time;
|
|
||||||
|
|
||||||
function f() public payable {
|
|
||||||
// FIXME: change now to block.timestamp
|
|
||||||
time = block.timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
contract E {
|
|
||||||
D d;
|
|
||||||
|
|
||||||
// FIXME: remove constructor visibility
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
function g() public {
|
|
||||||
// FIXME: change .value(5) => {value: 5}
|
|
||||||
d.f{value: 5}();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +1,4 @@
|
|||||||
add_executable(solidity-upgrade
|
|
||||||
solidityUpgrade/main.cpp
|
|
||||||
solidityUpgrade/UpgradeChange.h
|
|
||||||
solidityUpgrade/UpgradeChange.cpp
|
|
||||||
solidityUpgrade/UpgradeSuite.h
|
|
||||||
solidityUpgrade/Upgrade050.cpp
|
|
||||||
solidityUpgrade/Upgrade060.cpp
|
|
||||||
solidityUpgrade/Upgrade070.cpp
|
|
||||||
solidityUpgrade/SourceTransform.h
|
|
||||||
solidityUpgrade/SourceUpgrade.cpp
|
|
||||||
)
|
|
||||||
target_link_libraries(solidity-upgrade PRIVATE solidity Boost::boost Boost::program_options Boost::system)
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
|
||||||
|
|
||||||
set(libphaser_sources
|
set(libphaser_sources
|
||||||
yulPhaser/Common.h
|
yulPhaser/Common.h
|
||||||
|
@ -1,309 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <libsolidity/analysis/OverrideChecker.h>
|
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
|
||||||
|
|
||||||
#include <liblangutil/CharStreamProvider.h>
|
|
||||||
#include <liblangutil/Scanner.h>
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
namespace solidity::tools
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper for displaying location during asserts
|
|
||||||
*/
|
|
||||||
class LocationHelper
|
|
||||||
{
|
|
||||||
std::stringstream m_stream;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
LocationHelper& operator<<(T const& data)
|
|
||||||
{
|
|
||||||
m_stream << data;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
operator std::string() { return m_stream.str(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class SourceTextRetriever
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit SourceTextRetriever(langutil::CharStreamProvider const& _charStreamProvider):
|
|
||||||
m_charStreamProvider(_charStreamProvider) {}
|
|
||||||
std::string text(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
solAssert(_location.hasText(), "");
|
|
||||||
return std::string{m_charStreamProvider.charStream(*_location.sourceName).text(_location)};
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
langutil::CharStreamProvider const& m_charStreamProvider;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 SourceTextRetriever
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using SourceTextRetriever::SourceTextRetriever;
|
|
||||||
|
|
||||||
bool isMultilineKeyword(
|
|
||||||
langutil::SourceLocation const& _location,
|
|
||||||
std::string const& _keyword
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
return regex_search(
|
|
||||||
text(_location),
|
|
||||||
std::regex{"(\\b" + _keyword + "\\b\\n|\\r|\\r\\n)"}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasMutabilityKeyword(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
return regex_search(
|
|
||||||
text(_location),
|
|
||||||
std::regex{"(\\b(pure|view|nonpayable|payable)\\b)"}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasVirtualKeyword(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
return regex_search(text(_location), std::regex{"(\\b(virtual)\\b)"});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasVisibilityKeyword(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
return regex_search(text(_location), 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() + ",";
|
|
||||||
|
|
||||||
// Note: Can create incorrect replacements
|
|
||||||
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 SourceTextRetriever
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using SourceTextRetriever::SourceTextRetriever;
|
|
||||||
|
|
||||||
/// Searches for the keyword given and prepends the expression.
|
|
||||||
/// E.g. `function f() view;` -> `function f() public view;`
|
|
||||||
std::string insertBeforeKeyword(
|
|
||||||
langutil::SourceLocation const& _location,
|
|
||||||
std::string const& _keyword,
|
|
||||||
std::string const& _expression
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
auto _regex = std::regex{"(\\b" + _keyword + "\\b)"};
|
|
||||||
if (regex_search(text(_location), _regex))
|
|
||||||
return regex_replace(
|
|
||||||
text(_location),
|
|
||||||
_regex,
|
|
||||||
_expression + " " + _keyword,
|
|
||||||
std::regex_constants::format_first_only
|
|
||||||
);
|
|
||||||
else
|
|
||||||
solAssert(
|
|
||||||
false,
|
|
||||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
|
||||||
"\nNeeds to be fixed manually."
|
|
||||||
);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Searches for the keyword given and appends the expression.
|
|
||||||
/// E.g. `function f() public {}` -> `function f() public override {}`
|
|
||||||
std::string insertAfterKeyword(
|
|
||||||
langutil::SourceLocation const& _location,
|
|
||||||
std::string const& _keyword,
|
|
||||||
std::string const& _expression
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
bool isMultiline = SourceAnalysis{m_charStreamProvider}.isMultilineKeyword(_location, _keyword);
|
|
||||||
std::string toAppend = isMultiline ? ("\n " + _expression) : (" " + _expression);
|
|
||||||
std::regex keyword{"(\\b" + _keyword + "\\b)"};
|
|
||||||
|
|
||||||
if (regex_search(text(_location), keyword))
|
|
||||||
return regex_replace(text(_location), keyword, _keyword + toAppend);
|
|
||||||
else
|
|
||||||
solAssert(
|
|
||||||
false,
|
|
||||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
|
||||||
"\nNeeds to be fixed manually."
|
|
||||||
);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Searches for the first right parenthesis and appends the expression
|
|
||||||
/// given.
|
|
||||||
/// E.g. `function f() {}` -> `function f() public {}`
|
|
||||||
std::string insertAfterRightParenthesis(
|
|
||||||
langutil::SourceLocation const& _location,
|
|
||||||
std::string const& _expression
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
auto _regex = std::regex{"(\\))"};
|
|
||||||
if (regex_search(text(_location), _regex))
|
|
||||||
return regex_replace(
|
|
||||||
text(_location),
|
|
||||||
std::regex{"(\\))"},
|
|
||||||
") " + _expression
|
|
||||||
);
|
|
||||||
else
|
|
||||||
solAssert(
|
|
||||||
false,
|
|
||||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
|
||||||
"\nNeeds to be fixed manually."
|
|
||||||
);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Searches for the `function` keyword and its identifier and replaces
|
|
||||||
/// both by the expression given.
|
|
||||||
/// E.g. `function Storage() {}` -> `constructor() {}`
|
|
||||||
std::string replaceFunctionName(
|
|
||||||
langutil::SourceLocation const& _location,
|
|
||||||
std::string const& _name,
|
|
||||||
std::string const& _expression
|
|
||||||
) const
|
|
||||||
{
|
|
||||||
auto _regex = std::regex{ "(\\bfunction\\s*" + _name + "\\b)"};
|
|
||||||
if (regex_search(text(_location), _regex))
|
|
||||||
return regex_replace(
|
|
||||||
text(_location),
|
|
||||||
_regex,
|
|
||||||
_expression
|
|
||||||
);
|
|
||||||
else
|
|
||||||
solAssert(
|
|
||||||
false,
|
|
||||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
|
||||||
"\nNeeds to be fixed manually."
|
|
||||||
);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string gasUpdate(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
// dot, "gas", any number of whitespaces, left bracket
|
|
||||||
std::regex gasReg{"\\.gas\\s*\\("};
|
|
||||||
|
|
||||||
if (regex_search(text(_location), gasReg))
|
|
||||||
{
|
|
||||||
std::string out = regex_replace(
|
|
||||||
text(_location),
|
|
||||||
gasReg,
|
|
||||||
"{gas: ",
|
|
||||||
std::regex_constants::format_first_only
|
|
||||||
);
|
|
||||||
return regex_replace(out, std::regex{"\\)$"}, "}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
solAssert(
|
|
||||||
false,
|
|
||||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
|
||||||
"\nNeeds to be fixed manually."
|
|
||||||
);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string valueUpdate(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
// dot, "value", any number of whitespaces, left bracket
|
|
||||||
std::regex valueReg{"\\.value\\s*\\("};
|
|
||||||
|
|
||||||
if (regex_search(text(_location), valueReg))
|
|
||||||
{
|
|
||||||
std::string out = regex_replace(
|
|
||||||
text(_location),
|
|
||||||
valueReg,
|
|
||||||
"{value: ",
|
|
||||||
std::regex_constants::format_first_only
|
|
||||||
);
|
|
||||||
return regex_replace(out, std::regex{"\\)$"}, "}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
solAssert(
|
|
||||||
false,
|
|
||||||
LocationHelper() << "Could not fix: " << text(_location) << " at " << _location <<
|
|
||||||
"\nNeeds to be fixed manually."
|
|
||||||
);
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string nowUpdate(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
return regex_replace(text(_location), std::regex{"now"}, "block.timestamp");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string removeVisibility(langutil::SourceLocation const& _location) const
|
|
||||||
{
|
|
||||||
std::string replacement = text(_location);
|
|
||||||
for (auto const& replace: {"public ", "public", "internal ", "internal", "external ", "external"})
|
|
||||||
replacement = regex_replace(replacement, std::regex{replace}, "");
|
|
||||||
return replacement;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,541 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#include <tools/solidityUpgrade/SourceUpgrade.h>
|
|
||||||
|
|
||||||
#include <liblangutil/Exceptions.h>
|
|
||||||
#include <liblangutil/SourceReferenceFormatter.h>
|
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
|
||||||
#include <boost/algorithm/string.hpp>
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#ifdef _WIN32 // windows
|
|
||||||
#include <io.h>
|
|
||||||
#define isatty _isatty
|
|
||||||
#define fileno _fileno
|
|
||||||
#else // unix
|
|
||||||
#include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
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 if (module == "dotsyntax")
|
|
||||||
m_suite.activateModule(Module::DotSyntax);
|
|
||||||
else if (module == "now")
|
|
||||||
m_suite.activateModule(Module::NowKeyword);
|
|
||||||
else if (module == "constructor-visibility")
|
|
||||||
m_suite.activateModule(Module::ConstrutorVisibility);
|
|
||||||
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& _exception)
|
|
||||||
{
|
|
||||||
error() << "Exception during compilation: " << boost::diagnostic_information(_exception) << endl;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
error() << "Unknown exception during compilation: " << boost::current_exception_diagnostic_information() << 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, m_compiler->ast(_sourceCode.first));
|
|
||||||
|
|
||||||
if (!m_suite.changes().empty())
|
|
||||||
{
|
|
||||||
auto& change = m_suite.changes().front();
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
change.log(*m_compiler, 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_sourceCodes[_sourceCode.first] = _change.apply(_sourceCode.second);
|
|
||||||
|
|
||||||
if (!dryRun)
|
|
||||||
writeInputFile(_sourceCode.first, m_sourceCodes[_sourceCode.first]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SourceUpgrade::printErrors() const
|
|
||||||
{
|
|
||||||
langutil::SourceReferenceFormatter formatter{cout, *m_compiler, true, false};
|
|
||||||
|
|
||||||
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>>())
|
|
||||||
{
|
|
||||||
boost::filesystem::path infile = 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_sourceCodes.size() == 0)
|
|
||||||
{
|
|
||||||
warning() << "No input files given." << 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
|
|
||||||
{
|
|
||||||
boost::filesystem::path path = _path;
|
|
||||||
boost::filesystem::path 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."};
|
|
||||||
|
|
||||||
string contents = readFileAsString(canonicalPath);
|
|
||||||
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: " + boost::current_exception_diagnostic_information()};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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 = std::make_unique<CompilerStack>(_callback);
|
|
||||||
m_compiler->setSources(m_sourceCodes);
|
|
||||||
m_compiler->setParserErrorRecovery(true);
|
|
||||||
}
|
|
@ -1,173 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
|
||||||
#include <tools/solidityUpgrade/Upgrade050.h>
|
|
||||||
#include <tools/solidityUpgrade/Upgrade060.h>
|
|
||||||
#include <tools/solidityUpgrade/Upgrade070.h>
|
|
||||||
|
|
||||||
#include <libsolidity/interface/CompilerStack.h>
|
|
||||||
#include <libsolidity/interface/DebugSettings.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,
|
|
||||||
DotSyntax,
|
|
||||||
NowKeyword,
|
|
||||||
ConstrutorVisibility
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Upgrade suite that hosts all available modules.
|
|
||||||
class Suite: public UpgradeSuite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void analyze(langutil::CharStreamProvider const& _charStreamProvider, frontend::SourceUnit const& _sourceUnit)
|
|
||||||
{
|
|
||||||
/// Solidity 0.5.0
|
|
||||||
if (isActivated(Module::ConstructorKeyword))
|
|
||||||
ConstructorKeyword{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
if (isActivated(Module::VisibilitySpecifier))
|
|
||||||
VisibilitySpecifier{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
|
|
||||||
/// Solidity 0.6.0
|
|
||||||
if (isActivated(Module::AbstractContract))
|
|
||||||
AbstractContract{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
if (isActivated(Module::OverridingFunction))
|
|
||||||
OverridingFunction{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
if (isActivated(Module::VirtualFunction))
|
|
||||||
VirtualFunction{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
|
|
||||||
/// Solidity 0.7.0
|
|
||||||
if (isActivated(Module::DotSyntax))
|
|
||||||
DotSyntax{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
if (isActivated(Module::NowKeyword))
|
|
||||||
NowKeyword{_charStreamProvider, m_changes}.analyze(_sourceUnit);
|
|
||||||
if (isActivated(Module::ConstrutorVisibility))
|
|
||||||
ConstructorVisibility{_charStreamProvider, 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,
|
|
||||||
Module::DotSyntax,
|
|
||||||
Module::NowKeyword,
|
|
||||||
Module::ConstrutorVisibility
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#include <tools/solidityUpgrade/Upgrade050.h>
|
|
||||||
#include <tools/solidityUpgrade/SourceTransform.h>
|
|
||||||
|
|
||||||
#include <libsolidity/analysis/OverrideChecker.h>
|
|
||||||
|
|
||||||
#include <libyul/AST.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.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
function->location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.replaceFunctionName(
|
|
||||||
function->location(),
|
|
||||||
function->name(),
|
|
||||||
"constructor"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisibilitySpecifier::endVisit(FunctionDefinition const& _function)
|
|
||||||
{
|
|
||||||
if (_function.noVisibilitySpecified())
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
_function.location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis(_function.location(), "public")
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#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) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,197 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#include <tools/solidityUpgrade/Upgrade060.h>
|
|
||||||
#include <tools/solidityUpgrade/SourceTransform.h>
|
|
||||||
|
|
||||||
#include <libsolidity/analysis/OverrideChecker.h>
|
|
||||||
|
|
||||||
#include <libyul/AST.h>
|
|
||||||
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
|
||||||
using namespace solidity::frontend;
|
|
||||||
using namespace solidity::tools;
|
|
||||||
|
|
||||||
void AbstractContract::endVisit(ContractDefinition const& _contract)
|
|
||||||
{
|
|
||||||
bool isFullyImplemented = _contract.annotation().unimplementedDeclarations->empty();
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isFullyImplemented &&
|
|
||||||
!_contract.abstract() &&
|
|
||||||
!_contract.isInterface()
|
|
||||||
)
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
_contract.location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.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.emplace_back(
|
|
||||||
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).asExternallyCallableFunction(false);
|
|
||||||
auto superType = super.externalFunctionType();
|
|
||||||
|
|
||||||
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.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
function->location(),
|
|
||||||
appendOverride(*function, expectedContracts)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string OverridingFunction::appendOverride(
|
|
||||||
FunctionDefinition const& _function,
|
|
||||||
Contracts const& _expectedContracts
|
|
||||||
)
|
|
||||||
{
|
|
||||||
auto location = _function.location();
|
|
||||||
string upgradedCode;
|
|
||||||
string overrideExpression = SourceGeneration::functionOverride(_expectedContracts);
|
|
||||||
|
|
||||||
if (SourceAnalysis{m_charStreamProvider}.hasVirtualKeyword(location))
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
|
||||||
location,
|
|
||||||
"virtual",
|
|
||||||
overrideExpression
|
|
||||||
);
|
|
||||||
else if (SourceAnalysis{m_charStreamProvider}.hasMutabilityKeyword(location))
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
|
||||||
location,
|
|
||||||
stateMutabilityToString(_function.stateMutability()),
|
|
||||||
overrideExpression
|
|
||||||
);
|
|
||||||
else if (SourceAnalysis{m_charStreamProvider}.hasVisibilityKeyword(location))
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
|
||||||
location,
|
|
||||||
Declaration::visibilityToString(_function.visibility()),
|
|
||||||
overrideExpression
|
|
||||||
);
|
|
||||||
else
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis(
|
|
||||||
location,
|
|
||||||
overrideExpression
|
|
||||||
);
|
|
||||||
|
|
||||||
return upgradedCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.emplace_back(
|
|
||||||
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.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
function->location(),
|
|
||||||
appendVirtual(*function)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string VirtualFunction::appendVirtual(FunctionDefinition const& _function) const
|
|
||||||
{
|
|
||||||
auto location = _function.location();
|
|
||||||
string upgradedCode;
|
|
||||||
|
|
||||||
if (SourceAnalysis{m_charStreamProvider}.hasMutabilityKeyword(location))
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
|
||||||
location,
|
|
||||||
stateMutabilityToString(_function.stateMutability()),
|
|
||||||
"virtual"
|
|
||||||
);
|
|
||||||
else if (SourceAnalysis{m_charStreamProvider}.hasVisibilityKeyword(location))
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterKeyword(
|
|
||||||
location,
|
|
||||||
Declaration::visibilityToString(_function.visibility()),
|
|
||||||
"virtual"
|
|
||||||
);
|
|
||||||
else
|
|
||||||
upgradedCode = SourceTransform{m_charStreamProvider}.insertAfterRightParenthesis(
|
|
||||||
_function.location(),
|
|
||||||
"virtual"
|
|
||||||
);
|
|
||||||
|
|
||||||
return upgradedCode;
|
|
||||||
}
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#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) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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:
|
|
||||||
using Contracts = std::set<frontend::ContractDefinition const*, frontend::OverrideChecker::CompareByID>;
|
|
||||||
|
|
||||||
void endVisit(frontend::ContractDefinition const& _contract) override;
|
|
||||||
|
|
||||||
std::string appendOverride(
|
|
||||||
frontend::FunctionDefinition const& _function,
|
|
||||||
Contracts const& _expectedContracts
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) override;
|
|
||||||
|
|
||||||
std::string appendVirtual(frontend::FunctionDefinition const& _function) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#include <tools/solidityUpgrade/Upgrade070.h>
|
|
||||||
#include <tools/solidityUpgrade/SourceTransform.h>
|
|
||||||
|
|
||||||
using namespace solidity::frontend;
|
|
||||||
using namespace solidity::tools;
|
|
||||||
|
|
||||||
void DotSyntax::endVisit(FunctionCall const& _functionCall)
|
|
||||||
{
|
|
||||||
Type const* type = _functionCall.annotation().type;
|
|
||||||
if (auto const funcType = dynamic_cast<FunctionType const*>(type))
|
|
||||||
{
|
|
||||||
if (funcType->valueSet())
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
_functionCall.location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.valueUpdate(_functionCall.location())
|
|
||||||
);
|
|
||||||
|
|
||||||
if (funcType->gasSet())
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
_functionCall.location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.gasUpdate(_functionCall.location())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NowKeyword::endVisit(Identifier const& _identifier)
|
|
||||||
{
|
|
||||||
IdentifierAnnotation& annotation = _identifier.annotation();
|
|
||||||
|
|
||||||
if (
|
|
||||||
MagicVariableDeclaration const* magicVar =
|
|
||||||
dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration)
|
|
||||||
)
|
|
||||||
if (magicVar->type()->category() == Type::Category::Integer)
|
|
||||||
{
|
|
||||||
solAssert(_identifier.name() == "now", "");
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
_identifier.location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.nowUpdate(_identifier.location())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConstructorVisibility::endVisit(ContractDefinition const& _contract)
|
|
||||||
{
|
|
||||||
if (!_contract.abstract())
|
|
||||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
|
||||||
if (
|
|
||||||
function->isConstructor() &&
|
|
||||||
!function->noVisibilitySpecified() &&
|
|
||||||
function->visibility() == Visibility::Internal
|
|
||||||
)
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
_contract.location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.insertBeforeKeyword(_contract.location(), "contract", "abstract")
|
|
||||||
);
|
|
||||||
|
|
||||||
for (FunctionDefinition const* function: _contract.definedFunctions())
|
|
||||||
if (function->isConstructor() && !function->noVisibilitySpecified())
|
|
||||||
m_changes.emplace_back(
|
|
||||||
UpgradeChange::Level::Safe,
|
|
||||||
function->location(),
|
|
||||||
SourceTransform{m_charStreamProvider}.removeVisibility(function->location())
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
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/UpgradeSuite.h>
|
|
||||||
|
|
||||||
#include <libsolidity/ast/AST.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NowKeyword: public AnalysisUpgrade
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using AnalysisUpgrade::AnalysisUpgrade;
|
|
||||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
|
||||||
private:
|
|
||||||
void endVisit(frontend::Identifier const& _expression) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConstructorVisibility: public AnalysisUpgrade
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using AnalysisUpgrade::AnalysisUpgrade;
|
|
||||||
void analyze(frontend::SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); }
|
|
||||||
private:
|
|
||||||
void endVisit(frontend::ContractDefinition const& _contract) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
|
||||||
|
|
||||||
#include <liblangutil/SourceReferenceExtractor.h>
|
|
||||||
#include <liblangutil/SourceReferenceFormatter.h>
|
|
||||||
#include <libsolutil/Numeric.h>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace solidity;
|
|
||||||
using namespace solidity::langutil;
|
|
||||||
using namespace solidity::util;
|
|
||||||
using namespace solidity::tools;
|
|
||||||
|
|
||||||
string UpgradeChange::apply(string _source) const
|
|
||||||
{
|
|
||||||
_source.replace(
|
|
||||||
static_cast<size_t>(m_location.start),
|
|
||||||
static_cast<size_t>(m_location.end - m_location.start),
|
|
||||||
m_patch
|
|
||||||
);
|
|
||||||
return _source;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpgradeChange::log(CharStreamProvider const& _charStreamProvider, bool const _shorten) const
|
|
||||||
{
|
|
||||||
stringstream os;
|
|
||||||
SourceReferenceFormatter formatter{os, _charStreamProvider, true, false};
|
|
||||||
|
|
||||||
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(_charStreamProvider, &m_location));
|
|
||||||
os << endl;
|
|
||||||
|
|
||||||
LineColumn lineEnd = _charStreamProvider.charStream(*m_location.sourceName).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(static_cast<size_t>(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;
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <liblangutil/CharStreamProvider.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
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_patch(std::move(_patch)),
|
|
||||||
m_level(_level)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~UpgradeChange() {}
|
|
||||||
|
|
||||||
langutil::SourceLocation const& location() const { return m_location; }
|
|
||||||
std::string patch() const { return m_patch; }
|
|
||||||
Level level() const { return m_level; }
|
|
||||||
|
|
||||||
/// Performs the actual replacement on the provided original source code
|
|
||||||
/// and returns the modified source code.
|
|
||||||
std::string apply(std::string _source) const;
|
|
||||||
/// Does a pretty-print of this upgrade change. Since the patch
|
|
||||||
/// can contain a lot of code lines, it can be shortened, which is signaled
|
|
||||||
/// by setting the flag.
|
|
||||||
void log(langutil::CharStreamProvider const& _charStreamProvider, bool const _shorten = true) const;
|
|
||||||
private:
|
|
||||||
langutil::SourceLocation m_location;
|
|
||||||
std::string m_patch;
|
|
||||||
Level m_level;
|
|
||||||
|
|
||||||
/// Shortens the given source to a constant limit.
|
|
||||||
static std::string shortenSource(std::string const& _source);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <tools/solidityUpgrade/UpgradeChange.h>
|
|
||||||
|
|
||||||
#include <liblangutil/ErrorReporter.h>
|
|
||||||
#include <liblangutil/CharStreamProvider.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(
|
|
||||||
langutil::CharStreamProvider const& _charStreamProvider,
|
|
||||||
std::vector<UpgradeChange>& _changes
|
|
||||||
): m_changes(_changes), m_charStreamProvider(_charStreamProvider) {}
|
|
||||||
|
|
||||||
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;
|
|
||||||
langutil::CharStreamProvider const& m_charStreamProvider;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A specific upgrade module meant to be run after the analysis phase
|
|
||||||
* of the compiler.
|
|
||||||
*/
|
|
||||||
class AnalysisUpgrade: public Upgrade, public frontend::ASTConstVisitor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AnalysisUpgrade(
|
|
||||||
langutil::CharStreamProvider const& _charStreamProvider,
|
|
||||||
std::vector<UpgradeChange>& _changes
|
|
||||||
):
|
|
||||||
Upgrade(_charStreamProvider, _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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
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() {}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
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() {}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
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
|
|
||||||
{}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
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 {}
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
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/>.
|
|
||||||
*/
|
|
||||||
// SPDX-License-Identifier: GPL-3.0
|
|
||||||
#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/exception/all.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();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!upgrade.processInput())
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
catch (boost::exception const& _exception)
|
|
||||||
{
|
|
||||||
cerr << "Exception while processing input:" << endl;
|
|
||||||
cerr << boost::diagnostic_information(_exception) << endl;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
cerr << "Uncaught exception while processing input:" << endl;
|
|
||||||
cerr << boost::current_exception_diagnostic_information() << endl;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user