mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #13778 from Andy53/removes-solidity-upgrade
Removes solidity upgrade
This commit is contained in:
commit
c195782f96
@ -173,11 +173,6 @@ defaults:
|
||||
- artifact_solc_windows: &artifact_solc_windows
|
||||
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
|
||||
path: build/tools/yul-phaser
|
||||
destination: yul-phaser
|
||||
@ -251,7 +246,6 @@ defaults:
|
||||
- checkout
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- store_artifacts: *artifact_solidity_upgrade
|
||||
- store_artifacts: *artifact_yul_phaser
|
||||
- persist_to_workspace: *artifacts_executables
|
||||
- gitter_notify_failure_unless_pr
|
||||
@ -952,7 +946,6 @@ jobs:
|
||||
<<: *steps_install_dependencies_osx
|
||||
- run: *run_build
|
||||
- store_artifacts: *artifacts_solc
|
||||
- store_artifacts: *artifact_solidity_upgrade
|
||||
- store_artifacts: *artifact_yul_phaser
|
||||
- persist_to_workspace:
|
||||
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: Make ``z3`` the default solver for the BMC and CHC engines instead of all solvers.
|
||||
* Parser: More detailed error messages about invalid version pragmas.
|
||||
* Removed support for the ``solidity-upgrade`` tool.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -630,229 +630,4 @@ Error Types
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
.. _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}();
|
||||
}
|
||||
}
|
||||
15. ``Info``: Information that the compiler thinks the user might find useful, but is not dangerous and does not necessarily need to be addressed.
|
@ -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)
|
||||
install(TARGETS solidity-upgrade DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
|
||||
set(libphaser_sources
|
||||
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