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:
andy53 2022-12-03 12:07:06 -07:00
parent 229fcc9fce
commit df2ea19535
21 changed files with 2 additions and 2232 deletions

View File

@ -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: .

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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;
}
};
}

View File

@ -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);
}

View File

@ -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;
};
}

View File

@ -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")
);
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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())
);
}

View File

@ -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;
};
}

View File

@ -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;
}

View File

@ -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);
};
}

View File

@ -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;
};
}

View File

@ -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() {}
}

View File

@ -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() {}
}

View File

@ -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
{}
}

View File

@ -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 {}
}

View File

@ -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;
}