mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Merge remote-tracking branch 'origin/develop' into develop_060
This commit is contained in:
		
						commit
						216e1749f4
					
				| @ -104,17 +104,6 @@ defaults: | |||||||
|       name: command line tests |       name: command line tests | ||||||
|       command: ./test/cmdlineTests.sh |       command: ./test/cmdlineTests.sh | ||||||
| 
 | 
 | ||||||
|   - test_ubuntu1904: &test_ubuntu1904 |  | ||||||
|       docker: |  | ||||||
|         - image: ethereum/solidity-buildpack-deps:ubuntu1904 |  | ||||||
|       steps: |  | ||||||
|         - checkout |  | ||||||
|         - attach_workspace: |  | ||||||
|             at: build |  | ||||||
|         - run: *run_soltest |  | ||||||
|         - store_test_results: *store_test_results |  | ||||||
|         - store_artifacts: *artifacts_test_results |  | ||||||
| 
 |  | ||||||
|   - test_ubuntu1904_clang: &test_ubuntu1904_clang |   - test_ubuntu1904_clang: &test_ubuntu1904_clang | ||||||
|       docker: |       docker: | ||||||
|         - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang |         - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang | ||||||
| @ -126,7 +115,7 @@ defaults: | |||||||
|         - store_test_results: *store_test_results |         - store_test_results: *store_test_results | ||||||
|         - store_artifacts: *artifacts_test_results |         - store_artifacts: *artifacts_test_results | ||||||
| 
 | 
 | ||||||
|   - test_ubuntu1904_all: &test_ubuntu1904 |   - test_ubuntu1904: &test_ubuntu1904 | ||||||
|       docker: |       docker: | ||||||
|         - image: ethereum/solidity-buildpack-deps:ubuntu1904 |         - image: ethereum/solidity-buildpack-deps:ubuntu1904 | ||||||
|       steps: |       steps: | ||||||
|  | |||||||
							
								
								
									
										18
									
								
								Changelog.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								Changelog.md
									
									
									
									
									
								
							| @ -36,23 +36,29 @@ Compiler Features: | |||||||
|  * Allow revert strings to be stripped from the binary using the ``--revert-strings`` option or the ``settings.debug.revertStrings`` setting. |  * Allow revert strings to be stripped from the binary using the ``--revert-strings`` option or the ``settings.debug.revertStrings`` setting. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### 0.5.13 (unreleased) | ### 0.5.13 (2019-11-14) | ||||||
| 
 | 
 | ||||||
| Language Features: | Language Features: | ||||||
|  |  * Allow to obtain the address of a linked library with ``address(LibraryName)``. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Compiler Features: | Compiler Features: | ||||||
|  * Code Generator: Use SELFBALANCE for ``address(this).balance`` if using Istanbul EVM |  * Code Generator: Use SELFBALANCE opcode for ``address(this).balance`` if using Istanbul EVM. | ||||||
|  |  * EWasm: Experimental EWasm binary output via ``--ewasm`` and as documented in standard-json. | ||||||
|  * SMTChecker: Add break/continue support to the CHC engine. |  * SMTChecker: Add break/continue support to the CHC engine. | ||||||
|  * SMTChecker: Support assignments to multi-dimensional arrays and mappings. |  * SMTChecker: Support assignments to multi-dimensional arrays and mappings. | ||||||
|  * SMTChecker: Support inheritance and function overriding. |  * SMTChecker: Support inheritance and function overriding. | ||||||
|  * EWasm: Experimental EWasm binary output. |  * Standard JSON Interface: Output the storage layout of a contract when artifact ``storageLayout`` is requested. | ||||||
|  |  * TypeChecker: List possible candidates when overload resolution fails. | ||||||
|  |  * TypeChecker: Disallow variables of library types. | ||||||
| 
 | 
 | ||||||
| Bugfixes: | Bugfixes: | ||||||
|  * Type Checker: Disallow constructor of the same class to be used as modifier |  * Code Generator: Fixed a faulty assert that would wrongly trigger for array sizes exceeding unsigned integer. | ||||||
|  * Code Generator: Fixed a faulty assert that would wrongly trigger for array sizes exceeding unsigned integer |  | ||||||
|  * Type Checker: Treat magic variables as unknown identifiers in inline assembly |  | ||||||
|  * SMTChecker: Fix internal error when accessing indices of fixed bytes. |  * SMTChecker: Fix internal error when accessing indices of fixed bytes. | ||||||
|  |  * SMTChecker: Fix internal error when using function pointers as arguments. | ||||||
|  |  * SMTChecker: Fix internal error when implicitly converting string literals to fixed bytes. | ||||||
|  |  * Type Checker: Disallow constructor of the same class to be used as modifier. | ||||||
|  |  * Type Checker: Treat magic variables as unknown identifiers in inline assembly. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### 0.5.12 (2019-10-01) | ### 0.5.12 (2019-10-01) | ||||||
|  | |||||||
| @ -754,6 +754,10 @@ | |||||||
|         "bugs": [], |         "bugs": [], | ||||||
|         "released": "2019-10-01" |         "released": "2019-10-01" | ||||||
|     }, |     }, | ||||||
|  |     "0.5.13": { | ||||||
|  |         "bugs": [], | ||||||
|  |         "released": "2019-11-14" | ||||||
|  |     }, | ||||||
|     "0.5.2": { |     "0.5.2": { | ||||||
|         "bugs": [ |         "bugs": [ | ||||||
|             "SignedArrayStorageCopy", |             "SignedArrayStorageCopy", | ||||||
|  | |||||||
| @ -178,6 +178,9 @@ custom types without the overhead of external function calls: | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | It is possible to obtain the address of a library by converting | ||||||
|  | the library type to the ``address`` type, i.e. using ``address(LibraryName)``. | ||||||
|  | 
 | ||||||
| As the compiler cannot know where the library will be | As the compiler cannot know where the library will be | ||||||
| deployed at, these addresses have to be filled into the | deployed at, these addresses have to be filled into the | ||||||
| final bytecode by a linker | final bytecode by a linker | ||||||
|  | |||||||
| @ -8,6 +8,8 @@ Miscellaneous | |||||||
| Layout of State Variables in Storage | Layout of State Variables in Storage | ||||||
| ************************************ | ************************************ | ||||||
| 
 | 
 | ||||||
|  | .. _storage-inplace-encoding: | ||||||
|  | 
 | ||||||
| Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position ``0``. Multiple, contiguous items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules: | Statically-sized variables (everything except mapping and dynamically-sized array types) are laid out contiguously in storage starting from position ``0``. Multiple, contiguous items that need less than 32 bytes are packed into a single storage slot if possible, according to the following rules: | ||||||
| 
 | 
 | ||||||
| - The first item in a storage slot is stored lower-order aligned. | - The first item in a storage slot is stored lower-order aligned. | ||||||
| @ -49,6 +51,8 @@ The elements of structs and arrays are stored after each other, just as if they | |||||||
| Mappings and Dynamic Arrays | Mappings and Dynamic Arrays | ||||||
| =========================== | =========================== | ||||||
| 
 | 
 | ||||||
|  | .. _storage-hashed-encoding: | ||||||
|  | 
 | ||||||
| Due to their unpredictable size, mapping and dynamically-sized array types use a Keccak-256 hash | Due to their unpredictable size, mapping and dynamically-sized array types use a Keccak-256 hash | ||||||
| computation to find the starting position of the value or the array data. These starting positions are always full stack slots. | computation to find the starting position of the value or the array data. These starting positions are always full stack slots. | ||||||
| 
 | 
 | ||||||
| @ -88,6 +92,267 @@ by checking if the lowest bit is set: short (not set) and long (set). | |||||||
| .. note:: | .. note:: | ||||||
|   Handling invalidly encoded slots is currently not supported but may be added in the future. |   Handling invalidly encoded slots is currently not supported but may be added in the future. | ||||||
| 
 | 
 | ||||||
|  | JSON Output | ||||||
|  | =========== | ||||||
|  | 
 | ||||||
|  | .. _storage-layout-top-level: | ||||||
|  | 
 | ||||||
|  | The storage layout of a contract can be requested via the :ref:`standard JSON interface <compiler-api>`.  The output is a JSON object containing two keys, | ||||||
|  | ``storage`` and ``types``.  The ``storage`` object is an array where each | ||||||
|  | element has the following form: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. code:: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         "astId": 2, | ||||||
|  |         "contract": "fileA:A", | ||||||
|  |         "label": "x", | ||||||
|  |         "offset": 0, | ||||||
|  |         "slot": "0", | ||||||
|  |         "type": "t_uint256" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | where the example above is the storage layout of ``contract A { uint x; }`` from source unit ``fileA`` | ||||||
|  | and | ||||||
|  | 
 | ||||||
|  | - ``astId`` is the id of the AST node of the state variable's declaration | ||||||
|  | - ``contract`` is the name of the contract including its path as prefix | ||||||
|  | - ``label`` is the name of the state variable | ||||||
|  | - ``offset`` is the offset in bytes within the storage slot according to the encoding | ||||||
|  | - ``slot`` is the storage slot where the state variable resides or starts. This | ||||||
|  |   number may be very large and therefore its JSON value is represented as a | ||||||
|  |   string. | ||||||
|  | - ``type`` is an identifier used as key to the variable's type information (described in the following) | ||||||
|  | 
 | ||||||
|  | The given ``type``, in this case ``t_uint256`` represents an element in | ||||||
|  | ``types``, which has the form: | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. code:: | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         "encoding": "inplace", | ||||||
|  |         "label": "uint256", | ||||||
|  |         "numberOfBytes": "32", | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | where | ||||||
|  | 
 | ||||||
|  | - ``encoding`` how the data is encoded in storage, where the possible values are: | ||||||
|  | 
 | ||||||
|  |   - ``inplace``: data is laid out contiguously in storage (see :ref:`above <storage-inplace-encoding>`). | ||||||
|  |   - ``mapping``: Keccak-256 hash-based method (see :ref:`above <storage-hashed-encoding>`). | ||||||
|  |   - ``dynamic_array``: Keccak-256 hash-based method (see :ref:`above <storage-hashed-encoding>`). | ||||||
|  |   - ``bytes``: single slot or Keccak-256 hash-based depending on the data size (see :ref:`above <bytes-and-string>`). | ||||||
|  | 
 | ||||||
|  | - ``label`` is the canonical type name. | ||||||
|  | - ``numberOfBytes`` is the number of used bytes (as a decimal string). Note that if ``numberOfBytes > 32`` this means that more than one slot is used. | ||||||
|  | 
 | ||||||
|  | Some types have extra information besides the four above. Mappings contain | ||||||
|  | its ``key`` and ``value`` types (again referencing an entry in this mapping | ||||||
|  | of types), arrays have its ``base`` type, and structs list their ``members`` in | ||||||
|  | the same format as the top-level ``storage`` (see :ref:`above | ||||||
|  | <storage-layout-top-level>`). | ||||||
|  | 
 | ||||||
|  | .. note :: | ||||||
|  |   The JSON output format of a contract's storage layout is still considered experimental | ||||||
|  |   and is subject to change in non-breaking releases of Solidity. | ||||||
|  | 
 | ||||||
|  | The following example shows a contract and its storage layout, containing | ||||||
|  | value and reference types, types that are encoded packed, and nested types. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | .. code:: | ||||||
|  | 
 | ||||||
|  |     pragma solidity >=0.4.0 <0.7.0; | ||||||
|  |     contract A { | ||||||
|  |         struct S { | ||||||
|  |             uint128 a; | ||||||
|  |             uint128 b; | ||||||
|  |             uint[2] staticArray; | ||||||
|  |             uint[] dynArray; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         uint x; | ||||||
|  |         uint y; | ||||||
|  |         S s; | ||||||
|  |         address addr; | ||||||
|  |         mapping (uint => mapping (address => bool)) map; | ||||||
|  |         uint[] array; | ||||||
|  |         string s1; | ||||||
|  |         bytes b1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | .. code:: | ||||||
|  | 
 | ||||||
|  |     "storageLayout": { | ||||||
|  |       "storage": [ | ||||||
|  |         { | ||||||
|  |           "astId": 14, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "x", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "0", | ||||||
|  |           "type": "t_uint256" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 16, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "y", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "1", | ||||||
|  |           "type": "t_uint256" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 18, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "s", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "2", | ||||||
|  |           "type": "t_struct(S)12_storage" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 20, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "addr", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "6", | ||||||
|  |           "type": "t_address" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 26, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "map", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "7", | ||||||
|  |           "type": "t_mapping(t_uint256,t_mapping(t_address,t_bool))" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 29, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "array", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "8", | ||||||
|  |           "type": "t_array(t_uint256)dyn_storage" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 31, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "s1", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "9", | ||||||
|  |           "type": "t_string_storage" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "astId": 33, | ||||||
|  |           "contract": "fileA:A", | ||||||
|  |           "label": "b1", | ||||||
|  |           "offset": 0, | ||||||
|  |           "slot": "10", | ||||||
|  |           "type": "t_bytes_storage" | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |       "types": { | ||||||
|  |         "t_address": { | ||||||
|  |           "encoding": "inplace", | ||||||
|  |           "label": "address", | ||||||
|  |           "numberOfBytes": "20" | ||||||
|  |         }, | ||||||
|  |         "t_array(t_uint256)2_storage": { | ||||||
|  |           "base": "t_uint256", | ||||||
|  |           "encoding": "inplace", | ||||||
|  |           "label": "uint256[2]", | ||||||
|  |           "numberOfBytes": "64" | ||||||
|  |         }, | ||||||
|  |         "t_array(t_uint256)dyn_storage": { | ||||||
|  |           "base": "t_uint256", | ||||||
|  |           "encoding": "dynamic_array", | ||||||
|  |           "label": "uint256[]", | ||||||
|  |           "numberOfBytes": "32" | ||||||
|  |         }, | ||||||
|  |         "t_bool": { | ||||||
|  |           "encoding": "inplace", | ||||||
|  |           "label": "bool", | ||||||
|  |           "numberOfBytes": "1" | ||||||
|  |         }, | ||||||
|  |         "t_bytes_storage": { | ||||||
|  |           "encoding": "bytes", | ||||||
|  |           "label": "bytes", | ||||||
|  |           "numberOfBytes": "32" | ||||||
|  |         }, | ||||||
|  |         "t_mapping(t_address,t_bool)": { | ||||||
|  |           "encoding": "mapping", | ||||||
|  |           "key": "t_address", | ||||||
|  |           "label": "mapping(address => bool)", | ||||||
|  |           "numberOfBytes": "32", | ||||||
|  |           "value": "t_bool" | ||||||
|  |         }, | ||||||
|  |         "t_mapping(t_uint256,t_mapping(t_address,t_bool))": { | ||||||
|  |           "encoding": "mapping", | ||||||
|  |           "key": "t_uint256", | ||||||
|  |           "label": "mapping(uint256 => mapping(address => bool))", | ||||||
|  |           "numberOfBytes": "32", | ||||||
|  |           "value": "t_mapping(t_address,t_bool)" | ||||||
|  |         }, | ||||||
|  |         "t_string_storage": { | ||||||
|  |           "encoding": "bytes", | ||||||
|  |           "label": "string", | ||||||
|  |           "numberOfBytes": "32" | ||||||
|  |         }, | ||||||
|  |         "t_struct(S)12_storage": { | ||||||
|  |           "encoding": "inplace", | ||||||
|  |           "label": "struct A.S", | ||||||
|  |           "members": [ | ||||||
|  |             { | ||||||
|  |               "astId": 2, | ||||||
|  |               "contract": "fileA:A", | ||||||
|  |               "label": "a", | ||||||
|  |               "offset": 0, | ||||||
|  |               "slot": "0", | ||||||
|  |               "type": "t_uint128" | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "astId": 4, | ||||||
|  |               "contract": "fileA:A", | ||||||
|  |               "label": "b", | ||||||
|  |               "offset": 16, | ||||||
|  |               "slot": "0", | ||||||
|  |               "type": "t_uint128" | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "astId": 8, | ||||||
|  |               "contract": "fileA:A", | ||||||
|  |               "label": "staticArray", | ||||||
|  |               "offset": 0, | ||||||
|  |               "slot": "1", | ||||||
|  |               "type": "t_array(t_uint256)2_storage" | ||||||
|  |             }, | ||||||
|  |             { | ||||||
|  |               "astId": 11, | ||||||
|  |               "contract": "fileA:A", | ||||||
|  |               "label": "dynArray", | ||||||
|  |               "offset": 0, | ||||||
|  |               "slot": "3", | ||||||
|  |               "type": "t_array(t_uint256)dyn_storage" | ||||||
|  |             } | ||||||
|  |           ], | ||||||
|  |           "numberOfBytes": "128" | ||||||
|  |         }, | ||||||
|  |         "t_uint128": { | ||||||
|  |           "encoding": "inplace", | ||||||
|  |           "label": "uint128", | ||||||
|  |           "numberOfBytes": "16" | ||||||
|  |         }, | ||||||
|  |         "t_uint256": { | ||||||
|  |           "encoding": "inplace", | ||||||
|  |           "label": "uint256", | ||||||
|  |           "numberOfBytes": "32" | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| .. index: memory layout | .. index: memory layout | ||||||
| 
 | 
 | ||||||
| **************** | **************** | ||||||
|  | |||||||
| @ -291,6 +291,7 @@ Input Description | |||||||
|         //   metadata - Metadata |         //   metadata - Metadata | ||||||
|         //   ir - Yul intermediate representation of the code before optimization |         //   ir - Yul intermediate representation of the code before optimization | ||||||
|         //   irOptimized - Intermediate representation after optimization |         //   irOptimized - Intermediate representation after optimization | ||||||
|  |         //   storageLayout - Slots, offsets and types of the contract's state variables. | ||||||
|         //   evm.assembly - New assembly format |         //   evm.assembly - New assembly format | ||||||
|         //   evm.legacyAssembly - Old-style assembly format in JSON |         //   evm.legacyAssembly - Old-style assembly format in JSON | ||||||
|         //   evm.bytecode.object - Bytecode object |         //   evm.bytecode.object - Bytecode object | ||||||
| @ -391,6 +392,8 @@ Output Description | |||||||
|             "devdoc": {}, |             "devdoc": {}, | ||||||
|             // Intermediate representation (string) |             // Intermediate representation (string) | ||||||
|             "ir": "", |             "ir": "", | ||||||
|  |             // See the Storage Layout documentation. | ||||||
|  |             "storageLayout": {"storage": [...], "types": {...} }, | ||||||
|             // EVM-related outputs |             // EVM-related outputs | ||||||
|             "evm": { |             "evm": { | ||||||
|               // Assembly (string) |               // Assembly (string) | ||||||
|  | |||||||
| @ -112,6 +112,8 @@ set(sources | |||||||
| 	interface/ReadFile.h | 	interface/ReadFile.h | ||||||
| 	interface/StandardCompiler.cpp | 	interface/StandardCompiler.cpp | ||||||
| 	interface/StandardCompiler.h | 	interface/StandardCompiler.h | ||||||
|  | 	interface/StorageLayout.cpp | ||||||
|  | 	interface/StorageLayout.h | ||||||
| 	interface/Version.cpp | 	interface/Version.cpp | ||||||
| 	interface/Version.h | 	interface/Version.h | ||||||
| 	parsing/DocStringParser.cpp | 	parsing/DocStringParser.cpp | ||||||
|  | |||||||
| @ -38,10 +38,12 @@ namespace solidity | |||||||
| 
 | 
 | ||||||
| NameAndTypeResolver::NameAndTypeResolver( | NameAndTypeResolver::NameAndTypeResolver( | ||||||
| 	GlobalContext& _globalContext, | 	GlobalContext& _globalContext, | ||||||
|  | 	langutil::EVMVersion _evmVersion, | ||||||
| 	map<ASTNode const*, shared_ptr<DeclarationContainer>>& _scopes, | 	map<ASTNode const*, shared_ptr<DeclarationContainer>>& _scopes, | ||||||
| 	ErrorReporter& _errorReporter | 	ErrorReporter& _errorReporter | ||||||
| ) : | ): | ||||||
| 	m_scopes(_scopes), | 	m_scopes(_scopes), | ||||||
|  | 	m_evmVersion(_evmVersion), | ||||||
| 	m_errorReporter(_errorReporter), | 	m_errorReporter(_errorReporter), | ||||||
| 	m_globalContext(_globalContext) | 	m_globalContext(_globalContext) | ||||||
| { | { | ||||||
| @ -324,7 +326,7 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res | |||||||
| 	{ | 	{ | ||||||
| 		if (m_scopes.count(&_node)) | 		if (m_scopes.count(&_node)) | ||||||
| 			setScope(&_node); | 			setScope(&_node); | ||||||
| 		return ReferencesResolver(m_errorReporter, *this, _resolveInsideCode).resolve(_node); | 		return ReferencesResolver(m_errorReporter, *this, m_evmVersion, _resolveInsideCode).resolve(_node); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -28,6 +28,8 @@ | |||||||
| #include <libsolidity/ast/ASTAnnotations.h> | #include <libsolidity/ast/ASTAnnotations.h> | ||||||
| #include <libsolidity/ast/ASTVisitor.h> | #include <libsolidity/ast/ASTVisitor.h> | ||||||
| 
 | 
 | ||||||
|  | #include <liblangutil/EVMVersion.h> | ||||||
|  | 
 | ||||||
| #include <boost/noncopyable.hpp> | #include <boost/noncopyable.hpp> | ||||||
| 
 | 
 | ||||||
| #include <list> | #include <list> | ||||||
| @ -55,6 +57,7 @@ public: | |||||||
| 	/// are filled during the lifetime of this object.
 | 	/// are filled during the lifetime of this object.
 | ||||||
| 	NameAndTypeResolver( | 	NameAndTypeResolver( | ||||||
| 		GlobalContext& _globalContext, | 		GlobalContext& _globalContext, | ||||||
|  | 		langutil::EVMVersion _evmVersion, | ||||||
| 		std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes, | 		std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes, | ||||||
| 		langutil::ErrorReporter& _errorReporter | 		langutil::ErrorReporter& _errorReporter | ||||||
| 	); | 	); | ||||||
| @ -130,6 +133,7 @@ private: | |||||||
| 	/// Aliases (for example `import "x" as y;`) create multiple pointers to the same scope.
 | 	/// Aliases (for example `import "x" as y;`) create multiple pointers to the same scope.
 | ||||||
| 	std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes; | 	std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes; | ||||||
| 
 | 
 | ||||||
|  | 	langutil::EVMVersion m_evmVersion; | ||||||
| 	DeclarationContainer* m_currentScope = nullptr; | 	DeclarationContainer* m_currentScope = nullptr; | ||||||
| 	langutil::ErrorReporter& m_errorReporter; | 	langutil::ErrorReporter& m_errorReporter; | ||||||
| 	GlobalContext& m_globalContext; | 	GlobalContext& m_globalContext; | ||||||
|  | |||||||
| @ -350,7 +350,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) | |||||||
| 	yul::AsmAnalyzer( | 	yul::AsmAnalyzer( | ||||||
| 		analysisInfo, | 		analysisInfo, | ||||||
| 		errorsIgnored, | 		errorsIgnored, | ||||||
| 		yul::EVMDialect::strictAssemblyForEVM(EVMVersion{}), | 		yul::EVMDialect::strictAssemblyForEVM(m_evmVersion), | ||||||
| 		resolver | 		resolver | ||||||
| 	).analyze(_inlineAssembly.operations()); | 	).analyze(_inlineAssembly.operations()); | ||||||
| 	return false; | 	return false; | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <libsolidity/ast/ASTVisitor.h> | #include <libsolidity/ast/ASTVisitor.h> | ||||||
| #include <libsolidity/ast/ASTAnnotations.h> | #include <libsolidity/ast/ASTAnnotations.h> | ||||||
|  | #include <liblangutil/EVMVersion.h> | ||||||
| 
 | 
 | ||||||
| #include <boost/noncopyable.hpp> | #include <boost/noncopyable.hpp> | ||||||
| #include <list> | #include <list> | ||||||
| @ -52,10 +53,12 @@ public: | |||||||
| 	ReferencesResolver( | 	ReferencesResolver( | ||||||
| 		langutil::ErrorReporter& _errorReporter, | 		langutil::ErrorReporter& _errorReporter, | ||||||
| 		NameAndTypeResolver& _resolver, | 		NameAndTypeResolver& _resolver, | ||||||
|  | 		langutil::EVMVersion _evmVersion, | ||||||
| 		bool _resolveInsideCode = false | 		bool _resolveInsideCode = false | ||||||
| 	): | 	): | ||||||
| 		m_errorReporter(_errorReporter), | 		m_errorReporter(_errorReporter), | ||||||
| 		m_resolver(_resolver), | 		m_resolver(_resolver), | ||||||
|  | 		m_evmVersion(_evmVersion), | ||||||
| 		m_resolveInsideCode(_resolveInsideCode) | 		m_resolveInsideCode(_resolveInsideCode) | ||||||
| 	{} | 	{} | ||||||
| 
 | 
 | ||||||
| @ -99,6 +102,7 @@ private: | |||||||
| 
 | 
 | ||||||
| 	langutil::ErrorReporter& m_errorReporter; | 	langutil::ErrorReporter& m_errorReporter; | ||||||
| 	NameAndTypeResolver& m_resolver; | 	NameAndTypeResolver& m_resolver; | ||||||
|  | 	langutil::EVMVersion m_evmVersion; | ||||||
| 	/// Stack of return parameters.
 | 	/// Stack of return parameters.
 | ||||||
| 	std::vector<ParameterList const*> m_returnParameters; | 	std::vector<ParameterList const*> m_returnParameters; | ||||||
| 	bool const m_resolveInsideCode; | 	bool const m_resolveInsideCode; | ||||||
|  | |||||||
| @ -457,6 +457,9 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) | |||||||
| 	TypePointer varType = _variable.annotation().type; | 	TypePointer varType = _variable.annotation().type; | ||||||
| 	solAssert(!!varType, "Variable type not provided."); | 	solAssert(!!varType, "Variable type not provided."); | ||||||
| 
 | 
 | ||||||
|  | 	if (auto contractType = dynamic_cast<ContractType const*>(varType)) | ||||||
|  | 		if (contractType->contractDefinition().isLibrary()) | ||||||
|  | 			m_errorReporter.typeError(_variable.location(), "The type of a variable cannot be a library."); | ||||||
| 	if (_variable.value()) | 	if (_variable.value()) | ||||||
| 		expectType(*_variable.value(), *varType); | 		expectType(*_variable.value(), *varType); | ||||||
| 	if (_variable.isConstant()) | 	if (_variable.isConstant()) | ||||||
| @ -2633,12 +2636,30 @@ bool TypeChecker::visit(Identifier const& _identifier) | |||||||
| 				if (functionType->canTakeArguments(*annotation.arguments)) | 				if (functionType->canTakeArguments(*annotation.arguments)) | ||||||
| 					candidates.push_back(declaration); | 					candidates.push_back(declaration); | ||||||
| 			} | 			} | ||||||
| 			if (candidates.empty()) | 			if (candidates.size() == 1) | ||||||
| 				m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after argument-dependent lookup."); |  | ||||||
| 			else if (candidates.size() == 1) |  | ||||||
| 				annotation.referencedDeclaration = candidates.front(); | 				annotation.referencedDeclaration = candidates.front(); | ||||||
| 			else | 			else | ||||||
| 				m_errorReporter.fatalTypeError(_identifier.location(), "No unique declaration found after argument-dependent lookup."); | 			{ | ||||||
|  | 				SecondarySourceLocation ssl; | ||||||
|  | 
 | ||||||
|  | 				for (Declaration const* declaration: annotation.overloadedDeclarations) | ||||||
|  | 					if (declaration->location().isEmpty()) | ||||||
|  | 					{ | ||||||
|  | 						// Try to re-construct function definition
 | ||||||
|  | 						string description; | ||||||
|  | 						for (auto const& param: declaration->functionType(true)->parameterTypes()) | ||||||
|  | 							description += (description.empty() ? "" : ", ") + param->toString(false); | ||||||
|  | 						description = "function " + _identifier.name() + "(" + description + ")"; | ||||||
|  | 
 | ||||||
|  | 						ssl.append("Candidate: " + description, declaration->location()); | ||||||
|  | 					} | ||||||
|  | 					else | ||||||
|  | 						ssl.append("Candidate:", declaration->location()); | ||||||
|  | 				if (candidates.empty()) | ||||||
|  | 					m_errorReporter.fatalTypeError(_identifier.location(), ssl, "No matching declaration found after argument-dependent lookup."); | ||||||
|  | 				else | ||||||
|  | 					m_errorReporter.fatalTypeError(_identifier.location(), ssl, "No unique declaration found after argument-dependent lookup."); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	solAssert( | 	solAssert( | ||||||
|  | |||||||
| @ -3411,6 +3411,15 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current | |||||||
| 	return members; | 	return members; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | BoolResult TypeType::isExplicitlyConvertibleTo(Type const& _convertTo) const | ||||||
|  | { | ||||||
|  | 	if (auto const* address = dynamic_cast<AddressType const*>(&_convertTo)) | ||||||
|  | 		if (address->stateMutability() == StateMutability::NonPayable) | ||||||
|  | 			if (auto const* contractType = dynamic_cast<ContractType const*>(m_actualType)) | ||||||
|  | 				return contractType->contractDefinition().isLibrary(); | ||||||
|  | 	return isImplicitlyConvertibleTo(_convertTo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| ModifierType::ModifierType(ModifierDefinition const& _modifier) | ModifierType::ModifierType(ModifierDefinition const& _modifier) | ||||||
| { | { | ||||||
| 	TypePointers params; | 	TypePointers params; | ||||||
|  | |||||||
| @ -1317,6 +1317,7 @@ public: | |||||||
| 	std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; } | 	std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; } | ||||||
| 	MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; | 	MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; | ||||||
| 
 | 
 | ||||||
|  | 	BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; | ||||||
| private: | private: | ||||||
| 	TypePointer m_actualType; | 	TypePointer m_actualType; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -475,7 +475,22 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | |||||||
| 	{ | 	{ | ||||||
| 		solAssert(_functionCall.arguments().size() == 1, ""); | 		solAssert(_functionCall.arguments().size() == 1, ""); | ||||||
| 		solAssert(_functionCall.names().empty(), ""); | 		solAssert(_functionCall.names().empty(), ""); | ||||||
| 		acceptAndConvert(*_functionCall.arguments().front(), *_functionCall.annotation().type); | 		auto const& expression = *_functionCall.arguments().front(); | ||||||
|  | 		auto const& targetType = *_functionCall.annotation().type; | ||||||
|  | 		if (auto const* typeType = dynamic_cast<TypeType const*>(expression.annotation().type)) | ||||||
|  | 			if (auto const* addressType = dynamic_cast<AddressType const*>(&targetType)) | ||||||
|  | 			{ | ||||||
|  | 				auto const* contractType = dynamic_cast<ContractType const*>(typeType->actualType()); | ||||||
|  | 				solAssert( | ||||||
|  | 					contractType && | ||||||
|  | 					contractType->contractDefinition().isLibrary() && | ||||||
|  | 					addressType->stateMutability() == StateMutability::NonPayable, | ||||||
|  | 					"" | ||||||
|  | 				); | ||||||
|  | 				m_context.appendLibraryAddress(contractType->contractDefinition().fullyQualifiedName()); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 		acceptAndConvert(expression, targetType); | ||||||
| 		return false; | 		return false; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -428,15 +428,20 @@ void BMC::inlineFunctionCall(FunctionCall const& _funCall) | |||||||
| 		auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type); | 		auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type); | ||||||
| 		solAssert(funType, ""); | 		solAssert(funType, ""); | ||||||
| 
 | 
 | ||||||
|  | 		auto const& functionParams = funDef->parameters(); | ||||||
|  | 		auto const& arguments = _funCall.arguments(); | ||||||
|  | 		unsigned firstParam = 0; | ||||||
| 		if (funType->bound()) | 		if (funType->bound()) | ||||||
| 		{ | 		{ | ||||||
| 			auto const& boundFunction = dynamic_cast<MemberAccess const*>(calledExpr); | 			auto const& boundFunction = dynamic_cast<MemberAccess const*>(calledExpr); | ||||||
| 			solAssert(boundFunction, ""); | 			solAssert(boundFunction, ""); | ||||||
| 			funArgs.push_back(expr(boundFunction->expression())); | 			funArgs.push_back(expr(boundFunction->expression(), functionParams.front()->type())); | ||||||
|  | 			firstParam = 1; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (auto arg: _funCall.arguments()) | 		solAssert((arguments.size() + firstParam) == functionParams.size(), ""); | ||||||
| 			funArgs.push_back(expr(*arg)); | 		for (unsigned i = 0; i < arguments.size(); ++i) | ||||||
|  | 			funArgs.push_back(expr(*arguments.at(i), functionParams.at(i + firstParam)->type())); | ||||||
| 		initializeFunctionCallParameters(*funDef, funArgs); | 		initializeFunctionCallParameters(*funDef, funArgs); | ||||||
| 
 | 
 | ||||||
| 		// The reason why we need to pushCallStack here instead of visit(FunctionDefinition)
 | 		// The reason why we need to pushCallStack here instead of visit(FunctionDefinition)
 | ||||||
|  | |||||||
| @ -508,7 +508,13 @@ smt::SortPointer CHC::sort(FunctionDefinition const& _function) | |||||||
| 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | ||||||
| 	vector<smt::SortPointer> varSorts; | 	vector<smt::SortPointer> varSorts; | ||||||
| 	for (auto const& var: _function.parameters() + _function.returnParameters()) | 	for (auto const& var: _function.parameters() + _function.returnParameters()) | ||||||
| 		varSorts.push_back(smt::smtSort(*var->type())); | 	{ | ||||||
|  | 		// SMT solvers do not support function types as arguments.
 | ||||||
|  | 		if (var->type()->category() == Type::Category::Function) | ||||||
|  | 			varSorts.push_back(make_shared<smt::Sort>(smt::Kind::Int)); | ||||||
|  | 		else | ||||||
|  | 			varSorts.push_back(smt::smtSort(*var->type())); | ||||||
|  | 	} | ||||||
| 	return make_shared<smt::FunctionSort>( | 	return make_shared<smt::FunctionSort>( | ||||||
| 		m_stateSorts + varSorts, | 		m_stateSorts + varSorts, | ||||||
| 		boolSort | 		boolSort | ||||||
| @ -526,7 +532,13 @@ smt::SortPointer CHC::sort(ASTNode const* _node) | |||||||
| 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | ||||||
| 	vector<smt::SortPointer> varSorts; | 	vector<smt::SortPointer> varSorts; | ||||||
| 	for (auto const& var: m_currentFunction->localVariables()) | 	for (auto const& var: m_currentFunction->localVariables()) | ||||||
| 		varSorts.push_back(smt::smtSort(*var->type())); | 	{ | ||||||
|  | 		// SMT solvers do not support function types as arguments.
 | ||||||
|  | 		if (var->type()->category() == Type::Category::Function) | ||||||
|  | 			varSorts.push_back(make_shared<smt::Sort>(smt::Kind::Int)); | ||||||
|  | 		else | ||||||
|  | 			varSorts.push_back(smt::smtSort(*var->type())); | ||||||
|  | 	} | ||||||
| 	return make_shared<smt::FunctionSort>( | 	return make_shared<smt::FunctionSort>( | ||||||
| 		fSort->domain + varSorts, | 		fSort->domain + varSorts, | ||||||
| 		boolSort | 		boolSort | ||||||
| @ -540,7 +552,7 @@ unique_ptr<smt::SymbolicFunctionVariable> CHC::createSymbolicBlock(smt::SortPoin | |||||||
| 		_name, | 		_name, | ||||||
| 		m_context | 		m_context | ||||||
| 	); | 	); | ||||||
| 	m_interface->registerRelation(block->currentValue()); | 	m_interface->registerRelation(block->currentFunctionValue()); | ||||||
| 	return block; | 	return block; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -572,7 +584,7 @@ smt::Expression CHC::error() | |||||||
| 
 | 
 | ||||||
| smt::Expression CHC::error(unsigned _idx) | smt::Expression CHC::error(unsigned _idx) | ||||||
| { | { | ||||||
| 	return m_errorPredicate->valueAtIndex(_idx)({}); | 	return m_errorPredicate->functionValueAtIndex(_idx)({}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| unique_ptr<smt::SymbolicFunctionVariable> CHC::createBlock(ASTNode const* _node, string const& _prefix) | unique_ptr<smt::SymbolicFunctionVariable> CHC::createBlock(ASTNode const* _node, string const& _prefix) | ||||||
| @ -589,7 +601,7 @@ void CHC::createErrorBlock() | |||||||
| { | { | ||||||
| 	solAssert(m_errorPredicate, ""); | 	solAssert(m_errorPredicate, ""); | ||||||
| 	m_errorPredicate->increaseIndex(); | 	m_errorPredicate->increaseIndex(); | ||||||
| 	m_interface->registerRelation(m_errorPredicate->currentValue()); | 	m_interface->registerRelation(m_errorPredicate->currentFunctionValue()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CHC::connectBlocks(smt::Expression const& _from, smt::Expression const& _to, smt::Expression const& _constraints) | void CHC::connectBlocks(smt::Expression const& _from, smt::Expression const& _to, smt::Expression const& _constraints) | ||||||
|  | |||||||
| @ -154,15 +154,15 @@ private: | |||||||
| 	//@{
 | 	//@{
 | ||||||
| 	/// Constructor predicate.
 | 	/// Constructor predicate.
 | ||||||
| 	/// Default constructor sets state vars to 0.
 | 	/// Default constructor sets state vars to 0.
 | ||||||
| 	std::unique_ptr<smt::SymbolicVariable> m_constructorPredicate; | 	std::unique_ptr<smt::SymbolicFunctionVariable> m_constructorPredicate; | ||||||
| 
 | 
 | ||||||
| 	/// Artificial Interface predicate.
 | 	/// Artificial Interface predicate.
 | ||||||
| 	/// Single entry block for all functions.
 | 	/// Single entry block for all functions.
 | ||||||
| 	std::unique_ptr<smt::SymbolicVariable> m_interfacePredicate; | 	std::unique_ptr<smt::SymbolicFunctionVariable> m_interfacePredicate; | ||||||
| 
 | 
 | ||||||
| 	/// Artificial Error predicate.
 | 	/// Artificial Error predicate.
 | ||||||
| 	/// Single error block for all assertions.
 | 	/// Single error block for all assertions.
 | ||||||
| 	std::unique_ptr<smt::SymbolicVariable> m_errorPredicate; | 	std::unique_ptr<smt::SymbolicFunctionVariable> m_errorPredicate; | ||||||
| 	//@}
 | 	//@}
 | ||||||
| 
 | 
 | ||||||
| 	/// Variables.
 | 	/// Variables.
 | ||||||
|  | |||||||
| @ -136,9 +136,13 @@ void SMTEncoder::visitFunctionOrModifier() | |||||||
| 			*modifierInvocation->name()->annotation().referencedDeclaration | 			*modifierInvocation->name()->annotation().referencedDeclaration | ||||||
| 		); | 		); | ||||||
| 		vector<smt::Expression> modifierArgsExpr; | 		vector<smt::Expression> modifierArgsExpr; | ||||||
| 		if (modifierInvocation->arguments()) | 		if (auto const* arguments = modifierInvocation->arguments()) | ||||||
| 			for (auto arg: *modifierInvocation->arguments()) | 		{ | ||||||
| 				modifierArgsExpr.push_back(expr(*arg)); | 			auto const& modifierParams = modifierDef.parameters(); | ||||||
|  | 			solAssert(modifierParams.size() == arguments->size(), ""); | ||||||
|  | 			for (unsigned i = 0; i < arguments->size(); ++i) | ||||||
|  | 				modifierArgsExpr.push_back(expr(*arguments->at(i), modifierParams.at(i)->type())); | ||||||
|  | 		} | ||||||
| 		initializeFunctionCallParameters(modifierDef, modifierArgsExpr); | 		initializeFunctionCallParameters(modifierDef, modifierArgsExpr); | ||||||
| 		pushCallStack({&modifierDef, modifierInvocation.get()}); | 		pushCallStack({&modifierDef, modifierInvocation.get()}); | ||||||
| 		modifierDef.body().accept(*this); | 		modifierDef.body().accept(*this); | ||||||
| @ -595,10 +599,10 @@ void SMTEncoder::endVisit(Identifier const& _identifier) | |||||||
| 	{ | 	{ | ||||||
| 		// Will be translated as part of the node that requested the lvalue.
 | 		// Will be translated as part of the node that requested the lvalue.
 | ||||||
| 	} | 	} | ||||||
| 	else if (_identifier.annotation().type->category() == Type::Category::Function) |  | ||||||
| 		visitFunctionIdentifier(_identifier); |  | ||||||
| 	else if (auto decl = identifierToVariable(_identifier)) | 	else if (auto decl = identifierToVariable(_identifier)) | ||||||
| 		defineExpr(_identifier, currentValue(*decl)); | 		defineExpr(_identifier, currentValue(*decl)); | ||||||
|  | 	else if (_identifier.annotation().type->category() == Type::Category::Function) | ||||||
|  | 		visitFunctionIdentifier(_identifier); | ||||||
| 	else if (_identifier.name() == "now") | 	else if (_identifier.name() == "now") | ||||||
| 		defineGlobalVariable(_identifier.name(), _identifier); | 		defineGlobalVariable(_identifier.name(), _identifier); | ||||||
| 	else if (_identifier.name() == "this") | 	else if (_identifier.name() == "this") | ||||||
| @ -699,7 +703,7 @@ void SMTEncoder::endVisit(Return const& _return) | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else if (returnParams.size() == 1) | 		else if (returnParams.size() == 1) | ||||||
| 			m_context.addAssertion(expr(*_return.expression()) == m_context.newValue(*returnParams.front())); | 			m_context.addAssertion(expr(*_return.expression(), returnParams.front()->type()) == m_context.newValue(*returnParams.front())); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -1353,7 +1357,7 @@ void SMTEncoder::createExpr(Expression const& _e) | |||||||
| void SMTEncoder::defineExpr(Expression const& _e, smt::Expression _value) | void SMTEncoder::defineExpr(Expression const& _e, smt::Expression _value) | ||||||
| { | { | ||||||
| 	createExpr(_e); | 	createExpr(_e); | ||||||
| 	solAssert(smt::smtKind(_e.annotation().type->category()) != smt::Kind::Function, "Equality operator applied to type that is not fully supported"); | 	solAssert(_value.sort->kind != smt::Kind::Function, "Equality operator applied to type that is not fully supported"); | ||||||
| 	m_context.addAssertion(expr(_e) == _value); | 	m_context.addAssertion(expr(_e) == _value); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ | |||||||
| 
 | 
 | ||||||
| #include <libsolidity/ast/TypeProvider.h> | #include <libsolidity/ast/TypeProvider.h> | ||||||
| #include <libsolidity/ast/Types.h> | #include <libsolidity/ast/Types.h> | ||||||
|  | #include <libdevcore/CommonData.h> | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
| @ -139,7 +140,28 @@ pair<bool, shared_ptr<SymbolicVariable>> newSymbolicVariable( | |||||||
| 	else if (isBool(_type.category())) | 	else if (isBool(_type.category())) | ||||||
| 		var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _context); | 		var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _context); | ||||||
| 	else if (isFunction(_type.category())) | 	else if (isFunction(_type.category())) | ||||||
| 		var = make_shared<SymbolicFunctionVariable>(type, _uniqueName, _context); | 	{ | ||||||
|  | 		auto const& fType = dynamic_cast<FunctionType const*>(type); | ||||||
|  | 		auto const& paramsIn = fType->parameterTypes(); | ||||||
|  | 		auto const& paramsOut = fType->returnParameterTypes(); | ||||||
|  | 		auto findFunctionParam = [&](auto&& params) { | ||||||
|  | 			return find_if( | ||||||
|  | 				begin(params), | ||||||
|  | 				end(params), | ||||||
|  | 				[&](TypePointer _paramType) { return _paramType->category() == solidity::Type::Category::Function; } | ||||||
|  | 			); | ||||||
|  | 		}; | ||||||
|  | 		if ( | ||||||
|  | 			findFunctionParam(paramsIn) != end(paramsIn) || | ||||||
|  | 			findFunctionParam(paramsOut) != end(paramsOut) | ||||||
|  | 		) | ||||||
|  | 		{ | ||||||
|  | 			abstract = true; | ||||||
|  | 			var = make_shared<SymbolicIntVariable>(TypeProvider::uint256(), type, _uniqueName, _context); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 			var = make_shared<SymbolicFunctionVariable>(type, _uniqueName, _context); | ||||||
|  | 	} | ||||||
| 	else if (isInteger(_type.category())) | 	else if (isInteger(_type.category())) | ||||||
| 		var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context); | 		var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context); | ||||||
| 	else if (isFixedBytes(_type.category())) | 	else if (isFixedBytes(_type.category())) | ||||||
|  | |||||||
| @ -19,7 +19,6 @@ | |||||||
| 
 | 
 | ||||||
| #include <libsolidity/formal/SymbolicTypes.h> | #include <libsolidity/formal/SymbolicTypes.h> | ||||||
| #include <libsolidity/ast/AST.h> | #include <libsolidity/ast/AST.h> | ||||||
| #include <libsolidity/ast/TypeProvider.h> |  | ||||||
| 
 | 
 | ||||||
| using namespace std; | using namespace std; | ||||||
| using namespace dev; | using namespace dev; | ||||||
| @ -153,16 +152,38 @@ SymbolicFunctionVariable::SymbolicFunctionVariable( | |||||||
| 	solAssert(m_sort->kind == Kind::Function, ""); | 	solAssert(m_sort->kind == Kind::Function, ""); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SymbolicFunctionVariable::resetDeclaration() | Expression SymbolicFunctionVariable::currentValue(solidity::TypePointer const& _targetType) const | ||||||
| { | { | ||||||
| 	m_declaration = m_context.newVariable(currentName(), m_sort); | 	return m_abstract.currentValue(_targetType); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Expression SymbolicFunctionVariable::currentFunctionValue() const | ||||||
|  | { | ||||||
|  | 	return m_declaration; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Expression SymbolicFunctionVariable::valueAtIndex(int _index) const | ||||||
|  | { | ||||||
|  | 	return m_abstract.valueAtIndex(_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Expression SymbolicFunctionVariable::functionValueAtIndex(int _index) const | ||||||
|  | { | ||||||
|  | 	return SymbolicVariable::valueAtIndex(_index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Expression SymbolicFunctionVariable::resetIndex() | ||||||
|  | { | ||||||
|  | 	SymbolicVariable::resetIndex(); | ||||||
|  | 	return m_abstract.resetIndex(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Expression SymbolicFunctionVariable::increaseIndex() | Expression SymbolicFunctionVariable::increaseIndex() | ||||||
| { | { | ||||||
| 	++(*m_ssa); | 	++(*m_ssa); | ||||||
| 	resetDeclaration(); | 	resetDeclaration(); | ||||||
| 	return currentValue(); | 	m_abstract.increaseIndex(); | ||||||
|  | 	return m_abstract.currentValue(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Expression SymbolicFunctionVariable::operator()(vector<Expression> _arguments) const | Expression SymbolicFunctionVariable::operator()(vector<Expression> _arguments) const | ||||||
| @ -170,6 +191,11 @@ Expression SymbolicFunctionVariable::operator()(vector<Expression> _arguments) c | |||||||
| 	return m_declaration(_arguments); | 	return m_declaration(_arguments); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void SymbolicFunctionVariable::resetDeclaration() | ||||||
|  | { | ||||||
|  | 	m_declaration = m_context.newVariable(currentName(), m_sort); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| SymbolicMappingVariable::SymbolicMappingVariable( | SymbolicMappingVariable::SymbolicMappingVariable( | ||||||
| 	solidity::TypePointer _type, | 	solidity::TypePointer _type, | ||||||
| 	string _uniqueName, | 	string _uniqueName, | ||||||
|  | |||||||
| @ -20,6 +20,7 @@ | |||||||
| #include <libsolidity/formal/SolverInterface.h> | #include <libsolidity/formal/SolverInterface.h> | ||||||
| #include <libsolidity/formal/SSAVariable.h> | #include <libsolidity/formal/SSAVariable.h> | ||||||
| #include <libsolidity/ast/Types.h> | #include <libsolidity/ast/Types.h> | ||||||
|  | #include <libsolidity/ast/TypeProvider.h> | ||||||
| #include <memory> | #include <memory> | ||||||
| 
 | 
 | ||||||
| namespace dev | namespace dev | ||||||
| @ -138,7 +139,12 @@ public: | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Specialization of SymbolicVariable for FunctionType |  * Specialization of SymbolicVariable for FunctionType. | ||||||
|  |  * Besides containing a symbolic function declaration, | ||||||
|  |  * it also has an integer used as abstraction. | ||||||
|  |  * By default, the abstract representation is used when | ||||||
|  |  * values are requested, and the function declaration is | ||||||
|  |  * used when operator() is applied over arguments. | ||||||
|  */ |  */ | ||||||
| class SymbolicFunctionVariable: public SymbolicVariable | class SymbolicFunctionVariable: public SymbolicVariable | ||||||
| { | { | ||||||
| @ -154,8 +160,20 @@ public: | |||||||
| 		EncodingContext& _context | 		EncodingContext& _context | ||||||
| 	); | 	); | ||||||
| 
 | 
 | ||||||
| 	Expression increaseIndex(); | 	Expression currentValue(solidity::TypePointer const& _targetType = TypePointer{}) const override; | ||||||
| 	Expression operator()(std::vector<Expression> _arguments) const; | 
 | ||||||
|  | 	// Explicit request the function declaration.
 | ||||||
|  | 	Expression currentFunctionValue() const; | ||||||
|  | 
 | ||||||
|  | 	Expression valueAtIndex(int _index) const override; | ||||||
|  | 
 | ||||||
|  | 	// Explicit request the function declaration.
 | ||||||
|  | 	Expression functionValueAtIndex(int _index) const; | ||||||
|  | 
 | ||||||
|  | 	Expression resetIndex() override; | ||||||
|  | 	Expression increaseIndex() override; | ||||||
|  | 
 | ||||||
|  | 	Expression operator()(std::vector<Expression> _arguments) const override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	/// Creates a new function declaration.
 | 	/// Creates a new function declaration.
 | ||||||
| @ -163,6 +181,14 @@ private: | |||||||
| 
 | 
 | ||||||
| 	/// Stores the current function declaration.
 | 	/// Stores the current function declaration.
 | ||||||
| 	Expression m_declaration; | 	Expression m_declaration; | ||||||
|  | 
 | ||||||
|  | 	/// Abstract representation.
 | ||||||
|  | 	SymbolicIntVariable m_abstract{ | ||||||
|  | 		TypeProvider::uint256(), | ||||||
|  | 		TypeProvider::uint256(), | ||||||
|  | 		m_uniqueName + "_abstract", | ||||||
|  | 		m_context | ||||||
|  | 	}; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ | |||||||
| #include <libsolidity/interface/ABI.h> | #include <libsolidity/interface/ABI.h> | ||||||
| #include <libsolidity/interface/Natspec.h> | #include <libsolidity/interface/Natspec.h> | ||||||
| #include <libsolidity/interface/GasEstimator.h> | #include <libsolidity/interface/GasEstimator.h> | ||||||
|  | #include <libsolidity/interface/StorageLayout.h> | ||||||
| #include <libsolidity/interface/Version.h> | #include <libsolidity/interface/Version.h> | ||||||
| #include <libsolidity/parsing/Parser.h> | #include <libsolidity/parsing/Parser.h> | ||||||
| 
 | 
 | ||||||
| @ -286,7 +287,7 @@ bool CompilerStack::analyze() | |||||||
| 				noErrors = false; | 				noErrors = false; | ||||||
| 
 | 
 | ||||||
| 		m_globalContext = make_shared<GlobalContext>(); | 		m_globalContext = make_shared<GlobalContext>(); | ||||||
| 		NameAndTypeResolver resolver(*m_globalContext, m_scopes, m_errorReporter); | 		NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_scopes, m_errorReporter); | ||||||
| 		for (Source const* source: m_sourceOrder) | 		for (Source const* source: m_sourceOrder) | ||||||
| 			if (!resolver.registerDeclarations(*source->ast)) | 			if (!resolver.registerDeclarations(*source->ast)) | ||||||
| 				return false; | 				return false; | ||||||
| @ -684,6 +685,28 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const | |||||||
| 	return *_contract.abi; | 	return *_contract.abi; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Json::Value const& CompilerStack::storageLayout(string const& _contractName) const | ||||||
|  | { | ||||||
|  | 	if (m_stackState < AnalysisPerformed) | ||||||
|  | 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); | ||||||
|  | 
 | ||||||
|  | 	return storageLayout(contract(_contractName)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Json::Value const& CompilerStack::storageLayout(Contract const& _contract) const | ||||||
|  | { | ||||||
|  | 	if (m_stackState < AnalysisPerformed) | ||||||
|  | 		BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); | ||||||
|  | 
 | ||||||
|  | 	solAssert(_contract.contract, ""); | ||||||
|  | 
 | ||||||
|  | 	// caches the result
 | ||||||
|  | 	if (!_contract.storageLayout) | ||||||
|  | 		_contract.storageLayout.reset(new Json::Value(StorageLayout().generate(*_contract.contract))); | ||||||
|  | 
 | ||||||
|  | 	return *_contract.storageLayout; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Json::Value const& CompilerStack::natspecUser(string const& _contractName) const | Json::Value const& CompilerStack::natspecUser(string const& _contractName) const | ||||||
| { | { | ||||||
| 	if (m_stackState < AnalysisPerformed) | 	if (m_stackState < AnalysisPerformed) | ||||||
|  | |||||||
| @ -287,6 +287,10 @@ public: | |||||||
| 	/// Prerequisite: Successful call to parse or compile.
 | 	/// Prerequisite: Successful call to parse or compile.
 | ||||||
| 	Json::Value const& contractABI(std::string const& _contractName) const; | 	Json::Value const& contractABI(std::string const& _contractName) const; | ||||||
| 
 | 
 | ||||||
|  | 	/// @returns a JSON representing the storage layout of the contract.
 | ||||||
|  | 	/// Prerequisite: Successful call to parse or compile.
 | ||||||
|  | 	Json::Value const& storageLayout(std::string const& _contractName) const; | ||||||
|  | 
 | ||||||
| 	/// @returns a JSON representing the contract's user documentation.
 | 	/// @returns a JSON representing the contract's user documentation.
 | ||||||
| 	/// Prerequisite: Successful call to parse or compile.
 | 	/// Prerequisite: Successful call to parse or compile.
 | ||||||
| 	Json::Value const& natspecUser(std::string const& _contractName) const; | 	Json::Value const& natspecUser(std::string const& _contractName) const; | ||||||
| @ -334,6 +338,7 @@ private: | |||||||
| 		eth::LinkerObject eWasmObject; ///< Experimental eWasm code
 | 		eth::LinkerObject eWasmObject; ///< Experimental eWasm code
 | ||||||
| 		mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
 | 		mutable std::unique_ptr<std::string const> metadata; ///< The metadata json that will be hashed into the chain.
 | ||||||
| 		mutable std::unique_ptr<Json::Value const> abi; | 		mutable std::unique_ptr<Json::Value const> abi; | ||||||
|  | 		mutable std::unique_ptr<Json::Value const> storageLayout; | ||||||
| 		mutable std::unique_ptr<Json::Value const> userDocumentation; | 		mutable std::unique_ptr<Json::Value const> userDocumentation; | ||||||
| 		mutable std::unique_ptr<Json::Value const> devDocumentation; | 		mutable std::unique_ptr<Json::Value const> devDocumentation; | ||||||
| 		mutable std::unique_ptr<std::string const> sourceMapping; | 		mutable std::unique_ptr<std::string const> sourceMapping; | ||||||
| @ -397,6 +402,10 @@ private: | |||||||
| 	/// This will generate the JSON object and store it in the Contract object if it is not present yet.
 | 	/// This will generate the JSON object and store it in the Contract object if it is not present yet.
 | ||||||
| 	Json::Value const& contractABI(Contract const&) const; | 	Json::Value const& contractABI(Contract const&) const; | ||||||
| 
 | 
 | ||||||
|  | 	/// @returns the storage layout of the contract as a JSON object.
 | ||||||
|  | 	/// This will generate the JSON object and store it in the Contract object if it is not present yet.
 | ||||||
|  | 	Json::Value const& storageLayout(Contract const&) const; | ||||||
|  | 
 | ||||||
| 	/// @returns the Natspec User documentation as a JSON object.
 | 	/// @returns the Natspec User documentation as a JSON object.
 | ||||||
| 	/// This will generate the JSON object and store it in the Contract object if it is not present yet.
 | 	/// This will generate the JSON object and store it in the Contract object if it is not present yet.
 | ||||||
| 	Json::Value const& natspecUser(Contract const&) const; | 	Json::Value const& natspecUser(Contract const&) const; | ||||||
|  | |||||||
| @ -927,10 +927,12 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting | |||||||
| 		string file = contractName.substr(0, colon); | 		string file = contractName.substr(0, colon); | ||||||
| 		string name = contractName.substr(colon + 1); | 		string name = contractName.substr(colon + 1); | ||||||
| 
 | 
 | ||||||
| 		// ABI, documentation and metadata
 | 		// ABI, storage layout, documentation and metadata
 | ||||||
| 		Json::Value contractData(Json::objectValue); | 		Json::Value contractData(Json::objectValue); | ||||||
| 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesExperimental)) | 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesExperimental)) | ||||||
| 			contractData["abi"] = compilerStack.contractABI(contractName); | 			contractData["abi"] = compilerStack.contractABI(contractName); | ||||||
|  | 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "storageLayout", false)) | ||||||
|  | 			contractData["storageLayout"] = compilerStack.storageLayout(contractName); | ||||||
| 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "metadata", wildcardMatchesExperimental)) | 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "metadata", wildcardMatchesExperimental)) | ||||||
| 			contractData["metadata"] = compilerStack.metadata(contractName); | 			contractData["metadata"] = compilerStack.metadata(contractName); | ||||||
| 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc", wildcardMatchesExperimental)) | 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "userdoc", wildcardMatchesExperimental)) | ||||||
|  | |||||||
							
								
								
									
										119
									
								
								libsolidity/interface/StorageLayout.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								libsolidity/interface/StorageLayout.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,119 @@ | |||||||
|  | /*
 | ||||||
|  | 	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/interface/StorageLayout.h> | ||||||
|  | 
 | ||||||
|  | #include <libsolidity/ast/TypeProvider.h> | ||||||
|  | 
 | ||||||
|  | using namespace std; | ||||||
|  | using namespace dev; | ||||||
|  | using namespace dev::solidity; | ||||||
|  | 
 | ||||||
|  | Json::Value StorageLayout::generate(ContractDefinition const& _contractDef) | ||||||
|  | { | ||||||
|  | 	solAssert(!m_contract, ""); | ||||||
|  | 	m_contract = &_contractDef; | ||||||
|  | 	m_types.clear(); | ||||||
|  | 
 | ||||||
|  | 	auto typeType = dynamic_cast<TypeType const*>(_contractDef.type()); | ||||||
|  | 	solAssert(typeType, ""); | ||||||
|  | 	auto contractType = dynamic_cast<ContractType const*>(typeType->actualType()); | ||||||
|  | 	solAssert(contractType, ""); | ||||||
|  | 
 | ||||||
|  | 	Json::Value variables(Json::arrayValue); | ||||||
|  | 	for (auto [var, slot, offset]: contractType->stateVariables()) | ||||||
|  | 		variables.append(generate(*var, slot, offset)); | ||||||
|  | 
 | ||||||
|  | 	Json::Value layout; | ||||||
|  | 	layout["storage"] = move(variables); | ||||||
|  | 	layout["types"] = move(m_types); | ||||||
|  | 	return layout; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Json::Value StorageLayout::generate(VariableDeclaration const& _var, u256 const& _slot, unsigned _offset) | ||||||
|  | { | ||||||
|  | 	Json::Value varEntry; | ||||||
|  | 	TypePointer varType = _var.type(); | ||||||
|  | 
 | ||||||
|  | 	varEntry["label"] = _var.name(); | ||||||
|  | 	varEntry["astId"] = int(_var.id()); | ||||||
|  | 	varEntry["contract"] = m_contract->fullyQualifiedName(); | ||||||
|  | 	varEntry["slot"] = _slot.str(); | ||||||
|  | 	varEntry["offset"] = _offset; | ||||||
|  | 	varEntry["type"] = typeKeyName(varType); | ||||||
|  | 
 | ||||||
|  | 	generate(varType); | ||||||
|  | 
 | ||||||
|  | 	return varEntry; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void StorageLayout::generate(TypePointer _type) | ||||||
|  | { | ||||||
|  | 	if (m_types.isMember(typeKeyName(_type))) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	// Register it now to cut recursive visits.
 | ||||||
|  | 	Json::Value& typeInfo = m_types[typeKeyName(_type)]; | ||||||
|  | 	typeInfo["label"] = _type->toString(true); | ||||||
|  | 	typeInfo["numberOfBytes"] = u256(_type->storageBytes() * _type->storageSize()).str(); | ||||||
|  | 
 | ||||||
|  | 	if (auto structType = dynamic_cast<StructType const*>(_type)) | ||||||
|  | 	{ | ||||||
|  | 		Json::Value members(Json::arrayValue); | ||||||
|  | 		auto const& structDef = structType->structDefinition(); | ||||||
|  | 		for (auto const& member: structDef.members()) | ||||||
|  | 		{ | ||||||
|  | 			auto const& offsets = structType->storageOffsetsOfMember(member->name()); | ||||||
|  | 			members.append(generate(*member, offsets.first, offsets.second)); | ||||||
|  | 		} | ||||||
|  | 		typeInfo["members"] = move(members); | ||||||
|  | 		typeInfo["encoding"] = "inplace"; | ||||||
|  | 	} | ||||||
|  | 	else if (auto mappingType = dynamic_cast<MappingType const*>(_type)) | ||||||
|  | 	{ | ||||||
|  | 		typeInfo["key"] = typeKeyName(mappingType->keyType()); | ||||||
|  | 		typeInfo["value"] = typeKeyName(mappingType->valueType()); | ||||||
|  | 		generate(mappingType->keyType()); | ||||||
|  | 		generate(mappingType->valueType()); | ||||||
|  | 		typeInfo["encoding"] = "mapping"; | ||||||
|  | 	} | ||||||
|  | 	else if (auto arrayType = dynamic_cast<ArrayType const*>(_type)) | ||||||
|  | 	{ | ||||||
|  | 		if (arrayType->isByteArray()) | ||||||
|  | 			typeInfo["encoding"] = "bytes"; | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			typeInfo["base"] = typeKeyName(arrayType->baseType()); | ||||||
|  | 			generate(arrayType->baseType()); | ||||||
|  | 			typeInfo["encoding"] = arrayType->isDynamicallySized() ? "dynamic_array" : "inplace"; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		solAssert(_type->isValueType(), ""); | ||||||
|  | 		typeInfo["encoding"] = "inplace"; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	solAssert(typeInfo.isMember("encoding"), ""); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | string StorageLayout::typeKeyName(TypePointer _type) | ||||||
|  | { | ||||||
|  | 	if (auto refType = dynamic_cast<ReferenceType const*>(_type)) | ||||||
|  | 		return TypeProvider::withLocationIfReference(refType->location(), _type)->richIdentifier(); | ||||||
|  | 	return _type->richIdentifier(); | ||||||
|  | } | ||||||
							
								
								
									
										58
									
								
								libsolidity/interface/StorageLayout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								libsolidity/interface/StorageLayout.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/>.
 | ||||||
|  | */ | ||||||
|  | /**
 | ||||||
|  |  * Generates the storage layout of a contract. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <libsolidity/ast/AST.h> | ||||||
|  | #include <libsolidity/ast/Types.h> | ||||||
|  | 
 | ||||||
|  | #include <json/json.h> | ||||||
|  | 
 | ||||||
|  | namespace dev | ||||||
|  | { | ||||||
|  | namespace solidity | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | class StorageLayout | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	/// Generates the storage layout of the contract
 | ||||||
|  | 	/// @param _contractDef The contract definition
 | ||||||
|  | 	/// @return A JSON representation of the contract's storage layout.
 | ||||||
|  | 	Json::Value generate(ContractDefinition const& _contractDef); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	/// Generates the JSON information for a variable and its storage location.
 | ||||||
|  | 	Json::Value generate(VariableDeclaration const& _var, u256 const& _slot, unsigned _offset); | ||||||
|  | 
 | ||||||
|  | 	/// Generates the JSON information for @param _type
 | ||||||
|  | 	void generate(TypePointer _type); | ||||||
|  | 
 | ||||||
|  | 	/// The key for the JSON object describing a type.
 | ||||||
|  | 	std::string typeKeyName(TypePointer _type); | ||||||
|  | 
 | ||||||
|  | 	Json::Value m_types; | ||||||
|  | 
 | ||||||
|  | 	/// Current analyzed contract
 | ||||||
|  | 	ContractDefinition const* m_contract = nullptr; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | } | ||||||
| @ -5,4 +5,4 @@ | |||||||
|         "compiler-fixed": "off", |         "compiler-fixed": "off", | ||||||
|         "no-inline-assembly": "off" |         "no-inline-assembly": "off" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								test/cmdlineTests/require_overload/err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								test/cmdlineTests/require_overload/err
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | require_overload/input.sol:4:9: Error: No matching declaration found after argument-dependent lookup. | ||||||
|  |         require(this); | ||||||
|  |         ^-----^ | ||||||
|  | Candidate: function require(bool) | ||||||
|  | Candidate: function require(bool, string memory) | ||||||
							
								
								
									
										1
									
								
								test/cmdlineTests/require_overload/exit
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								test/cmdlineTests/require_overload/exit
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | 1 | ||||||
							
								
								
									
										6
									
								
								test/cmdlineTests/require_overload/input.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								test/cmdlineTests/require_overload/input.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | pragma solidity >=0.0; | ||||||
|  | contract C { | ||||||
|  |     function f() public pure { | ||||||
|  |         require(this); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_bytes/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_bytes/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { bytes s1 = \"test\"; bytes s2; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_bytes/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_bytes/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_bytes_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_bytes_storage"}],"types":{"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { bytes s1 = \"test\"; bytes s2; } | ||||||
|  | ^-----------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":43,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_dyn_array/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_dyn_array/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { uint[] array1; bool[] array2; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_dyn_array/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_dyn_array/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"array1","offset":0,"slot":"0","type":"t_array(t_uint256)dyn_storage"},{"astId":6,"contract":"fileA:A","label":"array2","offset":0,"slot":"1","type":"t_array(t_bool)dyn_storage"}],"types":{"t_array(t_bool)dyn_storage":{"base":"t_bool","encoding":"dynamic_array","label":"bool[]","numberOfBytes":"32"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { uint[] array1; bool[] array2; } | ||||||
|  | ^------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":44,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_many/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_many/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; mapping (uint => mapping (address => bool)) map; uint[] array; string s1; bytes b1; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_many/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_many/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"},{"astId":26,"contract":"fileA:A","label":"map","offset":0,"slot":"7","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"},{"astId":29,"contract":"fileA:A","label":"array","offset":0,"slot":"8","type":"t_array(t_uint256)dyn_storage"},{"astId":31,"contract":"fileA:A","label":"s1","offset":0,"slot":"9","type":"t_string_storage"},{"astId":33,"contract":"fileA:A","label":"b1","offset":0,"slot":"10","type":"t_bytes_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_bytes_storage":{"encoding":"bytes","label":"bytes","numberOfBytes":"32"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { struct S { uint128 a;  ... int[] array; string s1; bytes b1; } | ||||||
|  | ^-------------------------------------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":206,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_mapping/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_mapping/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_mapping/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_mapping/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":10,"contract":"fileA:A","label":"map","offset":0,"slot":"2","type":"t_mapping(t_uint256,t_mapping(t_address,t_bool))"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_bool":{"encoding":"inplace","label":"bool","numberOfBytes":"1"},"t_mapping(t_address,t_bool)":{"encoding":"mapping","key":"t_address","label":"mapping(address => bool)","numberOfBytes":"32","value":"t_bool"},"t_mapping(t_uint256,t_mapping(t_address,t_bool))":{"encoding":"mapping","key":"t_uint256","label":"mapping(uint256 => mapping(address => bool))","numberOfBytes":"32","value":"t_mapping(t_address,t_bool)"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { uint x; uint y; mapping (uint => mapping (address => bool)) map; } | ||||||
|  | ^-----------------------------------------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":79,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_smoke/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_smoke/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_smoke/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_smoke/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { } | ||||||
|  | ^------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":14,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
| @ -0,0 +1,19 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { }" | ||||||
|  | 		}, | ||||||
|  | 		"fileB": { | ||||||
|  | 			"content": "contract A { uint x; uint y; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[],"types":null}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { } | ||||||
|  | ^------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":14,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0},"fileB":{"id":1}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_string/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_string/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { string s1 = \"test\"; string s2; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_string/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_string/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":3,"contract":"fileA:A","label":"s1","offset":0,"slot":"0","type":"t_string_storage"},{"astId":5,"contract":"fileA:A","label":"s2","offset":0,"slot":"1","type":"t_string_storage"}],"types":{"t_string_storage":{"encoding":"bytes","label":"string","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { string s1 = \"test\"; string s2; } | ||||||
|  | ^-------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":45,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_struct/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_struct/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_struct/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_struct/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"7","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"b","offset":0,"slot":"1","type":"t_uint256"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"2","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"4","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"160"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { struct S { uint a; uint b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; } | ||||||
|  | ^------------------------------------------------------------------------------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":116,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_struct_packed/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_struct_packed/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":14,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":16,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":18,"contract":"fileA:A","label":"s","offset":0,"slot":"2","type":"t_struct(S)12_storage"},{"astId":20,"contract":"fileA:A","label":"addr","offset":0,"slot":"6","type":"t_address"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_array(t_uint256)dyn_storage":{"base":"t_uint256","encoding":"dynamic_array","label":"uint256[]","numberOfBytes":"32"},"t_struct(S)12_storage":{"encoding":"inplace","label":"struct A.S","members":[{"astId":2,"contract":"fileA:A","label":"a","offset":0,"slot":"0","type":"t_uint128"},{"astId":4,"contract":"fileA:A","label":"b","offset":16,"slot":"0","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"staticArray","offset":0,"slot":"1","type":"t_array(t_uint256)2_storage"},{"astId":11,"contract":"fileA:A","label":"dynArray","offset":0,"slot":"3","type":"t_array(t_uint256)dyn_storage"}],"numberOfBytes":"128"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { struct S { uint128 a; uint128 b; uint[2] staticArray; uint[] dynArray; } uint x; uint y; S s; address addr; } | ||||||
|  | ^------------------------------------------------------------------------------------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":122,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
							
								
								
									
										16
									
								
								test/cmdlineTests/storage_layout_value_types/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								test/cmdlineTests/storage_layout_value_types/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { uint x; uint y; address addr; uint[2] array; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								test/cmdlineTests/storage_layout_value_types/output.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								test/cmdlineTests/storage_layout_value_types/output.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint256"},{"astId":4,"contract":"fileA:A","label":"y","offset":0,"slot":"1","type":"t_uint256"},{"astId":6,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":10,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { uint x; uint y; address addr; uint[2] array; } | ||||||
|  | ^---------------------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":59,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | { | ||||||
|  | 	"language": "Solidity", | ||||||
|  | 	"sources": { | ||||||
|  | 		"fileA": { | ||||||
|  | 			"content": "contract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; }" | ||||||
|  | 		} | ||||||
|  | 	}, | ||||||
|  | 	"settings": { | ||||||
|  | 		"outputSelection": { | ||||||
|  | 			"fileA": { | ||||||
|  | 				"A": [ "storageLayout" ], | ||||||
|  | 				"": [ "storageLayout" ] | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,4 @@ | |||||||
|  | {"contracts":{"fileA":{"A":{"storageLayout":{"storage":[{"astId":2,"contract":"fileA:A","label":"x","offset":0,"slot":"0","type":"t_uint64"},{"astId":4,"contract":"fileA:A","label":"y","offset":8,"slot":"0","type":"t_uint128"},{"astId":6,"contract":"fileA:A","label":"z","offset":0,"slot":"1","type":"t_uint128"},{"astId":8,"contract":"fileA:A","label":"addr","offset":0,"slot":"2","type":"t_address"},{"astId":12,"contract":"fileA:A","label":"array","offset":0,"slot":"3","type":"t_array(t_uint256)2_storage"}],"types":{"t_address":{"encoding":"inplace","label":"address","numberOfBytes":"20"},"t_array(t_uint256)2_storage":{"base":"t_uint256","encoding":"inplace","label":"uint256[2]","numberOfBytes":"64"},"t_uint128":{"encoding":"inplace","label":"uint128","numberOfBytes":"16"},"t_uint256":{"encoding":"inplace","label":"uint256","numberOfBytes":"32"},"t_uint64":{"encoding":"inplace","label":"uint64","numberOfBytes":"8"}}}}}},"errors":[{"component":"general","formattedMessage":"fileA:1:1: Warning: Source file does not specify required compiler version! | ||||||
|  | contract A { uint64 x; uint128 y; uint128 z; address addr; uint[2] array; } | ||||||
|  | ^-------------------------------------------------------------------------^ | ||||||
|  | ","message":"Source file does not specify required compiler version!","severity":"warning","sourceLocation":{"end":75,"file":"fileA","start":0},"type":"Warning"}],"sources":{"fileA":{"id":0}}} | ||||||
| @ -1,9 +1,14 @@ | |||||||
|  | contract X {} | ||||||
| library test { | library test { | ||||||
|     struct StructType { uint a; } |     struct StructType { uint a; } | ||||||
|     function f(StructType storage b, uint[] storage c, test d) public returns (uint[] memory e, StructType storage f) { f = f; } |     function f(StructType storage b, uint[] storage c, X d) public returns (uint[] memory e, StructType storage f) { f = f; } | ||||||
|     function f1(uint[] memory c, test d) public pure returns (uint[] memory e) {  } |     function f1(uint[] memory c, X d) public pure returns (uint[] memory e) {  } | ||||||
| } | } | ||||||
| // ---- | // ---- | ||||||
|  | //     :X | ||||||
|  | // [] | ||||||
|  | // | ||||||
|  | // | ||||||
| //     :test | //     :test | ||||||
| // [ | // [ | ||||||
| //   { | //   { | ||||||
| @ -15,9 +20,9 @@ library test { | |||||||
| //         "type": "uint256[]" | //         "type": "uint256[]" | ||||||
| //       }, | //       }, | ||||||
| //       { | //       { | ||||||
| //         "internalType": "library test", | //         "internalType": "contract X", | ||||||
| //         "name": "d", | //         "name": "d", | ||||||
| //         "type": "test" | //         "type": "X" | ||||||
| //       } | //       } | ||||||
| //     ], | //     ], | ||||||
| //     "name": "f1", | //     "name": "f1", | ||||||
|  | |||||||
| @ -64,7 +64,7 @@ eth::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode) | |||||||
| 
 | 
 | ||||||
| 	map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes; | 	map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes; | ||||||
| 	GlobalContext globalContext; | 	GlobalContext globalContext; | ||||||
| 	NameAndTypeResolver resolver(globalContext, scopes, errorReporter); | 	NameAndTypeResolver resolver(globalContext, dev::test::Options::get().evmVersion(), scopes, errorReporter); | ||||||
| 	solAssert(Error::containsOnlyWarnings(errorReporter.errors()), ""); | 	solAssert(Error::containsOnlyWarnings(errorReporter.errors()), ""); | ||||||
| 	resolver.registerDeclarations(*sourceUnit); | 	resolver.registerDeclarations(*sourceUnit); | ||||||
| 	for (ASTPointer<ASTNode> const& node: sourceUnit->nodes()) | 	for (ASTPointer<ASTNode> const& node: sourceUnit->nodes()) | ||||||
|  | |||||||
| @ -78,15 +78,34 @@ TestCase::TestResult SemanticTest::run(ostream& _stream, string const& _linePref | |||||||
| 		for (auto& test: m_tests) | 		for (auto& test: m_tests) | ||||||
| 			test.reset(); | 			test.reset(); | ||||||
| 
 | 
 | ||||||
|  | 		map<string, dev::test::Address> libraries; | ||||||
|  | 
 | ||||||
|  | 		bool constructed = false; | ||||||
|  | 
 | ||||||
| 		for (auto& test: m_tests) | 		for (auto& test: m_tests) | ||||||
| 		{ | 		{ | ||||||
| 			if (&test == &m_tests.front()) | 			if (constructed) | ||||||
| 				if (test.call().isConstructor) | 			{ | ||||||
| 					deploy("", test.call().value, test.call().arguments.rawBytes()); | 				soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); | ||||||
| 				else | 				soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments."); | ||||||
| 					soltestAssert(deploy("", 0, bytes()), "Failed to deploy contract."); | 			} | ||||||
|  | 			else if (test.call().isLibrary) | ||||||
|  | 			{ | ||||||
|  | 				soltestAssert( | ||||||
|  | 					deploy(test.call().signature, 0, {}, libraries) && m_transactionSuccessful, | ||||||
|  | 					"Failed to deploy library " + test.call().signature | ||||||
|  | 				); | ||||||
|  | 				libraries[test.call().signature] = m_contractAddress; | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 			else | 			else | ||||||
| 				soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call."); | 			{ | ||||||
|  | 				if (test.call().isConstructor) | ||||||
|  | 					deploy("", test.call().value, test.call().arguments.rawBytes(), libraries); | ||||||
|  | 				else | ||||||
|  | 					soltestAssert(deploy("", 0, bytes(), libraries), "Failed to deploy contract."); | ||||||
|  | 				constructed = true; | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			if (test.call().isConstructor) | 			if (test.call().isConstructor) | ||||||
| 			{ | 			{ | ||||||
| @ -171,8 +190,8 @@ void SemanticTest::parseExpectations(istream& _stream) | |||||||
| 	std::move(functionCalls.begin(), functionCalls.end(), back_inserter(m_tests)); | 	std::move(functionCalls.begin(), functionCalls.end(), back_inserter(m_tests)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool SemanticTest::deploy(string const& _contractName, u256 const& _value, bytes const& _arguments) | bool SemanticTest::deploy(string const& _contractName, u256 const& _value, bytes const& _arguments, map<string, dev::test::Address> const& _libraries) | ||||||
| { | { | ||||||
| 	auto output = compileAndRunWithoutCheck(m_source, _value, _contractName, _arguments); | 	auto output = compileAndRunWithoutCheck(m_source, _value, _contractName, _arguments, _libraries); | ||||||
| 	return !output.empty() && m_transactionSuccessful; | 	return !output.empty() && m_transactionSuccessful; | ||||||
| } | } | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ public: | |||||||
| 
 | 
 | ||||||
| 	/// Compiles and deploys currently held source.
 | 	/// Compiles and deploys currently held source.
 | ||||||
| 	/// Returns true if deployment was successful, false otherwise.
 | 	/// Returns true if deployment was successful, false otherwise.
 | ||||||
| 	bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments); | 	bool deploy(std::string const& _contractName, u256 const& _value, bytes const& _arguments, std::map<std::string, dev::test::Address> const& _libraries = {}); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| 	std::string m_source; | 	std::string m_source; | ||||||
|  | |||||||
| @ -118,7 +118,7 @@ bytes compileFirstExpression( | |||||||
| 	ErrorReporter errorReporter(errors); | 	ErrorReporter errorReporter(errors); | ||||||
| 	GlobalContext globalContext; | 	GlobalContext globalContext; | ||||||
| 	map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes; | 	map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes; | ||||||
| 	NameAndTypeResolver resolver(globalContext, scopes, errorReporter); | 	NameAndTypeResolver resolver(globalContext, dev::test::Options::get().evmVersion(), scopes, errorReporter); | ||||||
| 	resolver.registerDeclarations(*sourceUnit); | 	resolver.registerDeclarations(*sourceUnit); | ||||||
| 
 | 
 | ||||||
| 	vector<ContractDefinition const*> inheritanceHierarchy; | 	vector<ContractDefinition const*> inheritanceHierarchy; | ||||||
|  | |||||||
							
								
								
									
										56
									
								
								test/libsolidity/semanticTests/libraries/library_address.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								test/libsolidity/semanticTests/libraries/library_address.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,56 @@ | |||||||
|  | library L { | ||||||
|  |     function f(uint256 v) external pure returns (uint) { | ||||||
|  |         return v * v; | ||||||
|  |     } | ||||||
|  |     function g(uint256 v) external returns (uint) { | ||||||
|  |         return v * v; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | contract C { | ||||||
|  |     function addr() public view returns (bool) { | ||||||
|  |         return address(L) == address(0); | ||||||
|  |     } | ||||||
|  |     function g(uint256 v) public view returns (uint256) { | ||||||
|  |         return L.f(v); | ||||||
|  |     } | ||||||
|  |     function h(uint256 v) public returns (uint256) { | ||||||
|  |         (bool success, bytes memory result) = address(L).delegatecall(abi.encodeWithSignature("f(uint256)", v)); | ||||||
|  |         assert(success); | ||||||
|  |         return abi.decode(result, (uint256)); | ||||||
|  |     } | ||||||
|  |     function i(uint256 v) public returns (uint256) { | ||||||
|  |         (bool success, bytes memory result) = address(L).call(abi.encodeWithSignature("f(uint256)", v)); | ||||||
|  |         assert(success); | ||||||
|  |         return abi.decode(result, (uint256)); | ||||||
|  |     } | ||||||
|  |     function j(uint256 v) public returns (uint256) { | ||||||
|  |         (bool success, bytes memory result) = address(L).delegatecall(abi.encodeWithSignature("g(uint256)", v)); | ||||||
|  |         assert(success); | ||||||
|  |         return abi.decode(result, (uint256)); | ||||||
|  |     } | ||||||
|  |     function k(uint256 v) public returns (uint256) { | ||||||
|  |         (bool success, bytes memory result) = address(L).call(abi.encodeWithSignature("g(uint256)", v)); | ||||||
|  |         assert(success); | ||||||
|  |         return abi.decode(result, (uint256)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // EVMVersion: >=byzantium | ||||||
|  | // ---- | ||||||
|  | // library: L | ||||||
|  | // addr() -> false | ||||||
|  | // g(uint256): 1 -> 1 | ||||||
|  | // g(uint256): 2 -> 4 | ||||||
|  | // g(uint256): 4 -> 16 | ||||||
|  | // h(uint256): 1 -> 1 | ||||||
|  | // h(uint256): 2 -> 4 | ||||||
|  | // h(uint256): 4 -> 16 | ||||||
|  | // i(uint256): 1 -> 1 | ||||||
|  | // i(uint256): 2 -> 4 | ||||||
|  | // i(uint256): 4 -> 16 | ||||||
|  | // j(uint256): 1 -> 1 | ||||||
|  | // j(uint256): 2 -> 4 | ||||||
|  | // j(uint256): 4 -> 16 | ||||||
|  | // k(uint256): 1 -> FAILURE | ||||||
|  | // k(uint256): 2 -> FAILURE | ||||||
|  | // k(uint256): 4 -> FAILURE | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | library L { | ||||||
|  |     function f(uint256 a, uint256 b) external { | ||||||
|  |         assert(a * a == b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | contract C { | ||||||
|  |     function addr() public view returns (bool) { | ||||||
|  |         return address(L) == address(0); | ||||||
|  |     } | ||||||
|  |     function g(uint256 a, uint256 b) public returns (bool) { | ||||||
|  |         (bool success,) = address(L).delegatecall(abi.encodeWithSignature("f(uint256,uint256)", a, b)); | ||||||
|  |         return success; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // library: L | ||||||
|  | // g(uint256,uint256): 1, 1 -> true | ||||||
|  | // g(uint256,uint256): 1, 2 -> false | ||||||
|  | // g(uint256,uint256): 2, 3 -> false | ||||||
|  | // g(uint256,uint256): 2, 4 -> true | ||||||
|  | // g(uint256,uint256): 2, 5 -> false | ||||||
|  | // g(uint256,uint256): 4, 15 -> false | ||||||
|  | // g(uint256,uint256): 4, 16 -> true | ||||||
|  | // g(uint256,uint256): 4, 17 -> false | ||||||
							
								
								
									
										13
									
								
								test/libsolidity/semanticTests/libraries/stub.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								test/libsolidity/semanticTests/libraries/stub.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | library L { | ||||||
|  |     function f(uint256 v) external returns (uint256) { return v*v; } | ||||||
|  | } | ||||||
|  | contract C { | ||||||
|  |     function g(uint256 v) external returns (uint256) { | ||||||
|  |         return L.f(v); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // library: L | ||||||
|  | // g(uint256): 1 -> 1 | ||||||
|  | // g(uint256): 2 -> 4 | ||||||
|  | // g(uint256): 4 -> 16 | ||||||
							
								
								
									
										12
									
								
								test/libsolidity/semanticTests/libraries/stub_internal.sol
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								test/libsolidity/semanticTests/libraries/stub_internal.sol
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | library L { | ||||||
|  |     function f(uint256 v) internal returns (uint256) { return v*v; } | ||||||
|  | } | ||||||
|  | contract C { | ||||||
|  |     function g(uint256 v) external returns (uint256) { | ||||||
|  |         return L.f(v); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // g(uint256): 1 -> 1 | ||||||
|  | // g(uint256): 2 -> 4 | ||||||
|  | // g(uint256): 4 -> 16 | ||||||
| @ -12,17 +12,33 @@ contract C { | |||||||
| 		x = true; | 		x = true; | ||||||
| 		require(true); | 		require(true); | ||||||
| 	} | 	} | ||||||
| 	/* Not properly supported by test system yet |  | ||||||
| 	function f2(bool a) public pure returns (bool x) { | 	function f2(bool a) public pure returns (bool x) { | ||||||
| 		x = a; | 		x = a; | ||||||
| 		string memory message; | 		string memory message; | ||||||
|  | 		message = "fancy message!"; | ||||||
| 		require(a, message); | 		require(a, message); | ||||||
| 	}*/ | 	} | ||||||
|  | 	function f3(bool a) public pure returns (bool x) { | ||||||
|  | 		x = a; | ||||||
|  | 		require(a, "msg"); | ||||||
|  | 	} | ||||||
|  | 	function f4(bool a) public pure returns (bool x) { | ||||||
|  | 		x = a; | ||||||
|  | 		string memory message; | ||||||
|  | 		require(a, message); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| // ==== | // ==== | ||||||
| // compileViaYul: true | // compileViaYul: also | ||||||
|  | // EVMVersion: >=byzantium | ||||||
| // ---- | // ---- | ||||||
| // f(bool): true -> true | // f(bool): true -> true | ||||||
| // f(bool): false -> FAILURE | // f(bool): false -> FAILURE | ||||||
| // fail() -> FAILURE | // fail() -> FAILURE | ||||||
| // succeed() -> true | // succeed() -> true | ||||||
|  | // f2(bool): true -> true | ||||||
|  | // f2(bool): false -> FAILURE, hex"08c379a0", 0x20, 14, "fancy message!" | ||||||
|  | // f3(bool): true -> true | ||||||
|  | // f3(bool): false -> FAILURE, hex"08c379a0", 0x20, 3, "msg" | ||||||
|  | // f4(bool): true -> true | ||||||
|  | // f4(bool): false -> FAILURE, hex"08c379a0", 0x20, 0 | ||||||
|  | |||||||
| @ -0,0 +1,10 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function f(address a, function(uint) external g) internal pure { | ||||||
|  | 		address b = address(g); | ||||||
|  | 		assert(a == b); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (128-138): Type conversion is not yet fully supported and might yield false positives. | ||||||
|  | // Warning: (142-156): Assertion violation happens here | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function f(function(uint) external returns (uint) g, function(uint) external returns (uint) h) public { | ||||||
|  | 		assert(g(2) == h(2)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (155-175): Assertion violation happens here | ||||||
| @ -0,0 +1,13 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function f(function(uint) returns (uint) g, function(uint) returns (uint) h) internal { | ||||||
|  | 		assert(g(2) == h(2)); | ||||||
|  | 		assert(g == h); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (146-150): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (154-158): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (170-176): Assertion checker does not yet implement the type function (uint256) returns (uint256) for comparisons | ||||||
|  | // Warning: (139-159): Assertion violation happens here | ||||||
|  | // Warning: (163-177): Assertion violation happens here | ||||||
| @ -0,0 +1,14 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract B { | ||||||
|  |     function f() pure public { | ||||||
|  | 		g("0123456"); | ||||||
|  | 	} | ||||||
|  |     function g(bytes7 a) pure public { | ||||||
|  | 		assert(a == "0123456"); | ||||||
|  | 		assert(a == "1234567"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (162-184): Assertion violation happens here | ||||||
|  | // Warning: (136-158): Assertion violation happens here | ||||||
|  | // Warning: (162-184): Assertion violation happens here | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract B { | ||||||
|  |     function f() mod2("0123456") pure public { } | ||||||
|  |     modifier mod2(bytes7 a) { | ||||||
|  | 		assert(a == "0123456"); | ||||||
|  | 		assert(a == "1234567"); | ||||||
|  | 		_; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (152-174): Assertion violation happens here | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function g() public pure returns (bytes32 val) { return "abc"; } | ||||||
|  |     function f1() public pure returns (bytes32 val) { return g(); } | ||||||
|  | 
 | ||||||
|  | 	function a() public pure { | ||||||
|  | 		assert(f1() == "abc"); | ||||||
|  | 		assert(f1() == "cde"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (238-259): Assertion violation happens here | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function h() public pure returns (bytes32 val, bytes3 val2) { return ("abc", "def"); } | ||||||
|  |     function g() public pure returns (bytes32 val) { return "abc"; } | ||||||
|  |     function f1() public pure returns (bytes32 val) { return g(); } | ||||||
|  |     function f2() public pure returns (bytes32 val, bytes3 val2) { return h(); } | ||||||
|  | 
 | ||||||
|  | 	function a() public pure { | ||||||
|  | 		(bytes32 v1, bytes3 v2) = f2(); | ||||||
|  | 		assert(v1 == "abc"); | ||||||
|  | 		assert(v2 == "cde"); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (442-461): Assertion violation happens here | ||||||
| @ -0,0 +1,5 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function f(function(uint) external g) public { | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,13 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  | 	function(uint) m_g; | ||||||
|  |     function f(function(uint) internal g) internal { | ||||||
|  | 		g(2); | ||||||
|  |     } | ||||||
|  | 	function h() public { | ||||||
|  | 		f(m_g); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (121-125): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (121-125): Assertion checker does not yet implement this type of function call. | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  |     function f(function(uint) external payable g) internal { | ||||||
|  | 		g.selector; | ||||||
|  | 		g.gas(2).value(3)(4); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (108-118): Assertion checker does not yet support this expression. | ||||||
|  | // Warning: (122-130): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (122-139): Assertion checker does not yet implement this type of function call. | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  | 	function(uint) m_g; | ||||||
|  |     function f1(function(uint) internal g1) internal { | ||||||
|  | 		g1(2); | ||||||
|  |     } | ||||||
|  |     function f2(function(function(uint) internal) internal g2) internal { | ||||||
|  | 		g2(m_g); | ||||||
|  |     } | ||||||
|  | 	function h() public { | ||||||
|  | 		f2(f1); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (123-128): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (152-197): Assertion checker does not yet support the type of this variable. | ||||||
|  | // Warning: (212-214): Assertion checker does not yet implement type function (function (uint256)) | ||||||
|  | // Warning: (212-219): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (255-257): Internal error: Expression undefined for SMT solver. | ||||||
|  | // Warning: (255-257): Assertion checker does not yet implement type function (function (uint256)) | ||||||
|  | // Warning: (212-214): Assertion checker does not yet implement type function (function (uint256)) | ||||||
|  | // Warning: (212-219): Assertion checker does not yet implement this type of function call. | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | pragma experimental SMTChecker; | ||||||
|  | contract C { | ||||||
|  | 	function(uint) m_g; | ||||||
|  | 	function r() internal view returns (function(uint)) { | ||||||
|  | 		return m_g; | ||||||
|  | 	} | ||||||
|  |     function f1(function(uint) internal g1) internal { | ||||||
|  | 		g1(2); | ||||||
|  |     } | ||||||
|  |     function f2(function(function(uint) internal) internal g2) internal { | ||||||
|  | 		g2(r()); | ||||||
|  |     } | ||||||
|  | 	function h() public { | ||||||
|  | 		f2(f1); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // Warning: (195-200): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (224-269): Assertion checker does not yet support the type of this variable. | ||||||
|  | // Warning: (284-286): Assertion checker does not yet implement type function (function (uint256)) | ||||||
|  | // Warning: (287-288): Assertion checker does not yet support this global variable. | ||||||
|  | // Warning: (284-291): Assertion checker does not yet implement this type of function call. | ||||||
|  | // Warning: (327-329): Internal error: Expression undefined for SMT solver. | ||||||
|  | // Warning: (327-329): Assertion checker does not yet implement type function (function (uint256)) | ||||||
|  | // Warning: (284-286): Assertion checker does not yet implement type function (function (uint256)) | ||||||
|  | // Warning: (287-288): Assertion checker does not yet support this global variable. | ||||||
|  | // Warning: (284-291): Assertion checker does not yet implement this type of function call. | ||||||
| @ -1,12 +1,12 @@ | |||||||
| contract C { | contract C { | ||||||
|     function f() pure external { |     function f() pure external returns (uint id) { | ||||||
|         assembly { |         assembly { | ||||||
|             pop(chainid()) |             id := chainid() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     function g() view external { |     function g() view external returns (uint sb) { | ||||||
|         assembly { |         assembly { | ||||||
|             pop(selfbalance()) |             sb := selfbalance() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,17 @@ | |||||||
|  | contract C { | ||||||
|  |     function f() pure external returns (uint id) { | ||||||
|  |         assembly { | ||||||
|  |             id := chainid() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     function g() view external returns (uint sb) { | ||||||
|  |         assembly { | ||||||
|  |             sb := selfbalance() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ==== | ||||||
|  | // EVMVersion: =petersburg | ||||||
|  | // ---- | ||||||
|  | // TypeError: (101-110): The "chainid" instruction is only available for Istanbul-compatible VMs  (you are currently compiling for "petersburg"). | ||||||
|  | // TypeError: (215-228): The "selfbalance" instruction is only available for Istanbul-compatible VMs  (you are currently compiling for "petersburg"). | ||||||
| @ -6,4 +6,5 @@ contract test { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| // ---- | // ---- | ||||||
|  | // TypeError: (87-90): The type of a variable cannot be a library. | ||||||
| // TypeError: (100-103): Member "l" not found or not visible after argument-dependent lookup in library L. | // TypeError: (100-103): Member "l" not found or not visible after argument-dependent lookup in library L. | ||||||
|  | |||||||
| @ -0,0 +1,14 @@ | |||||||
|  | library X { } | ||||||
|  | 
 | ||||||
|  | contract Y { | ||||||
|  | 	X abc; | ||||||
|  | 	function foo(X param) private view | ||||||
|  | 	{ | ||||||
|  | 		X ofg; | ||||||
|  | 		ofg = abc; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // TypeError: (29-34): The type of a variable cannot be a library. | ||||||
|  | // TypeError: (50-57): The type of a variable cannot be a library. | ||||||
|  | // TypeError: (77-82): The type of a variable cannot be a library. | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | library L { | ||||||
|  | } | ||||||
|  | contract C { | ||||||
|  |     function f() public pure returns (address) { | ||||||
|  |         return address(L); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | library L { | ||||||
|  | } | ||||||
|  | contract C { | ||||||
|  |     function f() public pure returns (address payable) { | ||||||
|  |         return address(L); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | // ---- | ||||||
|  | // TypeError: (99-109): Return argument type address is not implicitly convertible to expected type (type of first return variable) address payable. | ||||||
| @ -58,6 +58,7 @@ namespace test | |||||||
| 	K(Boolean, "boolean", 0)       \ | 	K(Boolean, "boolean", 0)       \ | ||||||
| 	/* special keywords */         \ | 	/* special keywords */         \ | ||||||
| 	K(Left, "left", 0)             \ | 	K(Left, "left", 0)             \ | ||||||
|  | 	K(Library, "library", 0)       \ | ||||||
| 	K(Right, "right", 0)           \ | 	K(Right, "right", 0)           \ | ||||||
| 	K(Failure, "FAILURE", 0)       \ | 	K(Failure, "FAILURE", 0)       \ | ||||||
| 
 | 
 | ||||||
| @ -268,6 +269,8 @@ struct FunctionCall | |||||||
| 	/// Marks this function call as "short-handed", meaning
 | 	/// Marks this function call as "short-handed", meaning
 | ||||||
| 	/// no `->` declared.
 | 	/// no `->` declared.
 | ||||||
| 	bool omitsArrow = true; | 	bool omitsArrow = true; | ||||||
|  | 	/// Marks a library deployment call.
 | ||||||
|  | 	bool isLibrary = false; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -75,44 +75,56 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls(siz | |||||||
| 
 | 
 | ||||||
| 				try | 				try | ||||||
| 				{ | 				{ | ||||||
| 					tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature(); | 					if (accept(Token::Library, true)) | ||||||
| 					if (accept(Token::Comma, true)) |  | ||||||
| 						call.value = parseFunctionCallValue(); |  | ||||||
| 					if (accept(Token::Colon, true)) |  | ||||||
| 						call.arguments = parseFunctionCallArguments(); |  | ||||||
| 
 |  | ||||||
| 					if (accept(Token::Newline, true)) |  | ||||||
| 					{ | 					{ | ||||||
| 						call.displayMode = FunctionCall::DisplayMode::MultiLine; | 						expect(Token::Colon); | ||||||
| 						m_lineNumber++; | 						call.signature = m_scanner.currentLiteral(); | ||||||
| 					} | 						expect(Token::Identifier); | ||||||
| 
 | 						call.isLibrary = true; | ||||||
| 					call.arguments.comment = parseComment(); | 						call.expectations.failure = false; | ||||||
| 
 |  | ||||||
| 					if (accept(Token::Newline, true)) |  | ||||||
| 					{ |  | ||||||
| 						call.displayMode = FunctionCall::DisplayMode::MultiLine; |  | ||||||
| 						m_lineNumber++; |  | ||||||
| 					} |  | ||||||
| 
 |  | ||||||
| 					if (accept(Token::Arrow, true)) |  | ||||||
| 					{ |  | ||||||
| 						call.omitsArrow = false; |  | ||||||
| 						call.expectations = parseFunctionCallExpectations(); |  | ||||||
| 						if (accept(Token::Newline, true)) |  | ||||||
| 							m_lineNumber++; |  | ||||||
| 					} | 					} | ||||||
| 					else | 					else | ||||||
| 					{ | 					{ | ||||||
| 						call.expectations.failure = false; | 						tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature(); | ||||||
| 						call.displayMode = FunctionCall::DisplayMode::SingleLine; | 						if (accept(Token::Comma, true)) | ||||||
|  | 							call.value = parseFunctionCallValue(); | ||||||
|  | 						if (accept(Token::Colon, true)) | ||||||
|  | 							call.arguments = parseFunctionCallArguments(); | ||||||
|  | 
 | ||||||
|  | 						if (accept(Token::Newline, true)) | ||||||
|  | 						{ | ||||||
|  | 							call.displayMode = FunctionCall::DisplayMode::MultiLine; | ||||||
|  | 							m_lineNumber++; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						call.arguments.comment = parseComment(); | ||||||
|  | 
 | ||||||
|  | 						if (accept(Token::Newline, true)) | ||||||
|  | 						{ | ||||||
|  | 							call.displayMode = FunctionCall::DisplayMode::MultiLine; | ||||||
|  | 							m_lineNumber++; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						if (accept(Token::Arrow, true)) | ||||||
|  | 						{ | ||||||
|  | 							call.omitsArrow = false; | ||||||
|  | 							call.expectations = parseFunctionCallExpectations(); | ||||||
|  | 							if (accept(Token::Newline, true)) | ||||||
|  | 								m_lineNumber++; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							call.expectations.failure = false; | ||||||
|  | 							call.displayMode = FunctionCall::DisplayMode::SingleLine; | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						call.expectations.comment = parseComment(); | ||||||
|  | 
 | ||||||
|  | 						if (call.signature == "constructor()") | ||||||
|  | 							call.isConstructor = true; | ||||||
|  | 
 | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					call.expectations.comment = parseComment(); |  | ||||||
| 
 |  | ||||||
| 					if (call.signature == "constructor()") |  | ||||||
| 						call.isConstructor = true; |  | ||||||
| 
 |  | ||||||
| 					calls.emplace_back(std::move(call)); | 					calls.emplace_back(std::move(call)); | ||||||
| 				} | 				} | ||||||
| 				catch (Error const& _e) | 				catch (Error const& _e) | ||||||
| @ -456,6 +468,7 @@ void TestFileParser::Scanner::scanNextToken() | |||||||
| 		if (_literal == "false") return TokenDesc{Token::Boolean, _literal}; | 		if (_literal == "false") return TokenDesc{Token::Boolean, _literal}; | ||||||
| 		if (_literal == "ether") return TokenDesc{Token::Ether, _literal}; | 		if (_literal == "ether") return TokenDesc{Token::Ether, _literal}; | ||||||
| 		if (_literal == "left") return TokenDesc{Token::Left, _literal}; | 		if (_literal == "left") return TokenDesc{Token::Left, _literal}; | ||||||
|  | 		if (_literal == "library") return TokenDesc{Token::Library, _literal}; | ||||||
| 		if (_literal == "right") return TokenDesc{Token::Right, _literal}; | 		if (_literal == "right") return TokenDesc{Token::Right, _literal}; | ||||||
| 		if (_literal == "hex") return TokenDesc{Token::Hex, _literal}; | 		if (_literal == "hex") return TokenDesc{Token::Hex, _literal}; | ||||||
| 		if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal}; | 		if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal}; | ||||||
|  | |||||||
| @ -57,7 +57,9 @@ void testFunctionCall( | |||||||
| 		u256 _value = 0, | 		u256 _value = 0, | ||||||
| 		string _argumentComment = "", | 		string _argumentComment = "", | ||||||
| 		string _expectationComment = "", | 		string _expectationComment = "", | ||||||
| 		vector<string> _rawArguments = vector<string>{} | 		vector<string> _rawArguments = vector<string>{}, | ||||||
|  | 		bool _isConstructor = false, | ||||||
|  | 		bool _isLibrary = false | ||||||
| ) | ) | ||||||
| { | { | ||||||
| 	BOOST_REQUIRE_EQUAL(_call.expectations.failure, _failure); | 	BOOST_REQUIRE_EQUAL(_call.expectations.failure, _failure); | ||||||
| @ -79,6 +81,9 @@ void testFunctionCall( | |||||||
| 			++index; | 			++index; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	BOOST_REQUIRE_EQUAL(_call.isConstructor, _isConstructor); | ||||||
|  | 	BOOST_REQUIRE_EQUAL(_call.isLibrary, _isLibrary); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOOST_AUTO_TEST_SUITE(TestFileParserTest) | BOOST_AUTO_TEST_SUITE(TestFileParserTest) | ||||||
| @ -883,6 +888,51 @@ BOOST_AUTO_TEST_CASE(call_unexpected_character) | |||||||
| 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | 	BOOST_REQUIRE_THROW(parse(source), langutil::Error); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(constructor) | ||||||
|  | { | ||||||
|  | 	char const* source = R"( | ||||||
|  | 		// constructor()
 | ||||||
|  | 	)"; | ||||||
|  | 	auto const calls = parse(source); | ||||||
|  | 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||||
|  | 	testFunctionCall( | ||||||
|  | 		calls.at(0), | ||||||
|  | 		Mode::SingleLine, | ||||||
|  | 		"constructor()", | ||||||
|  | 		false, | ||||||
|  | 		{}, | ||||||
|  | 		{}, | ||||||
|  | 		0, | ||||||
|  | 		"", | ||||||
|  | 		"", | ||||||
|  | 		{}, | ||||||
|  | 		true | ||||||
|  | 	); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOST_AUTO_TEST_CASE(library) | ||||||
|  | { | ||||||
|  | 	char const* source = R"( | ||||||
|  | 		// library: L
 | ||||||
|  | 	)"; | ||||||
|  | 	auto const calls = parse(source); | ||||||
|  | 	BOOST_REQUIRE_EQUAL(calls.size(), 1); | ||||||
|  | 	testFunctionCall( | ||||||
|  | 		calls.at(0), | ||||||
|  | 		Mode::SingleLine, | ||||||
|  | 		"L", | ||||||
|  | 		false, | ||||||
|  | 		{}, | ||||||
|  | 		{}, | ||||||
|  | 		0, | ||||||
|  | 		"", | ||||||
|  | 		"", | ||||||
|  | 		{}, | ||||||
|  | 		false, | ||||||
|  | 		true | ||||||
|  | 	); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -55,6 +55,12 @@ string TestFunctionCall::format( | |||||||
| 		string newline = formatToken(Token::Newline); | 		string newline = formatToken(Token::Newline); | ||||||
| 		string failure = formatToken(Token::Failure); | 		string failure = formatToken(Token::Failure); | ||||||
| 
 | 
 | ||||||
|  | 		if (m_call.isLibrary) | ||||||
|  | 		{ | ||||||
|  | 			stream << _linePrefix << newline << ws << "library:" << ws << m_call.signature; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		/// Formats the function signature. This is the same independent from the display-mode.
 | 		/// Formats the function signature. This is the same independent from the display-mode.
 | ||||||
| 		stream << _linePrefix << newline << ws << m_call.signature; | 		stream << _linePrefix << newline << ws << m_call.signature; | ||||||
| 		if (m_call.value > u256(0)) | 		if (m_call.value > u256(0)) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user