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