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 | ||||
|       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 | ||||
|       docker: | ||||
|         - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang | ||||
| @ -126,7 +115,7 @@ defaults: | ||||
|         - store_test_results: *store_test_results | ||||
|         - store_artifacts: *artifacts_test_results | ||||
| 
 | ||||
|   - test_ubuntu1904_all: &test_ubuntu1904 | ||||
|   - test_ubuntu1904: &test_ubuntu1904 | ||||
|       docker: | ||||
|         - image: ethereum/solidity-buildpack-deps:ubuntu1904 | ||||
|       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. | ||||
| 
 | ||||
| 
 | ||||
| ### 0.5.13 (unreleased) | ||||
| ### 0.5.13 (2019-11-14) | ||||
| 
 | ||||
| Language Features: | ||||
|  * Allow to obtain the address of a linked library with ``address(LibraryName)``. | ||||
| 
 | ||||
| 
 | ||||
| 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: Support assignments to multi-dimensional arrays and mappings. | ||||
|  * 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: | ||||
|  * 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 | ||||
|  * Type Checker: Treat magic variables as unknown identifiers in inline assembly | ||||
|  * Code Generator: Fixed a faulty assert that would wrongly trigger for array sizes exceeding unsigned integer. | ||||
|  * 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) | ||||
|  | ||||
| @ -754,6 +754,10 @@ | ||||
|         "bugs": [], | ||||
|         "released": "2019-10-01" | ||||
|     }, | ||||
|     "0.5.13": { | ||||
|         "bugs": [], | ||||
|         "released": "2019-11-14" | ||||
|     }, | ||||
|     "0.5.2": { | ||||
|         "bugs": [ | ||||
|             "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 | ||||
| deployed at, these addresses have to be filled into the | ||||
| final bytecode by a linker | ||||
|  | ||||
| @ -8,6 +8,8 @@ Miscellaneous | ||||
| 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: | ||||
| 
 | ||||
| - 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 | ||||
| =========================== | ||||
| 
 | ||||
| .. _storage-hashed-encoding: | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| @ -88,6 +92,267 @@ by checking if the lowest bit is set: short (not set) and long (set). | ||||
| .. note:: | ||||
|   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 | ||||
| 
 | ||||
| **************** | ||||
|  | ||||
| @ -291,6 +291,7 @@ Input Description | ||||
|         //   metadata - Metadata | ||||
|         //   ir - Yul intermediate representation of the code before optimization | ||||
|         //   irOptimized - Intermediate representation after optimization | ||||
|         //   storageLayout - Slots, offsets and types of the contract's state variables. | ||||
|         //   evm.assembly - New assembly format | ||||
|         //   evm.legacyAssembly - Old-style assembly format in JSON | ||||
|         //   evm.bytecode.object - Bytecode object | ||||
| @ -391,6 +392,8 @@ Output Description | ||||
|             "devdoc": {}, | ||||
|             // Intermediate representation (string) | ||||
|             "ir": "", | ||||
|             // See the Storage Layout documentation. | ||||
|             "storageLayout": {"storage": [...], "types": {...} }, | ||||
|             // EVM-related outputs | ||||
|             "evm": { | ||||
|               // Assembly (string) | ||||
|  | ||||
| @ -112,6 +112,8 @@ set(sources | ||||
| 	interface/ReadFile.h | ||||
| 	interface/StandardCompiler.cpp | ||||
| 	interface/StandardCompiler.h | ||||
| 	interface/StorageLayout.cpp | ||||
| 	interface/StorageLayout.h | ||||
| 	interface/Version.cpp | ||||
| 	interface/Version.h | ||||
| 	parsing/DocStringParser.cpp | ||||
|  | ||||
| @ -38,10 +38,12 @@ namespace solidity | ||||
| 
 | ||||
| NameAndTypeResolver::NameAndTypeResolver( | ||||
| 	GlobalContext& _globalContext, | ||||
| 	langutil::EVMVersion _evmVersion, | ||||
| 	map<ASTNode const*, shared_ptr<DeclarationContainer>>& _scopes, | ||||
| 	ErrorReporter& _errorReporter | ||||
| ) : | ||||
| ): | ||||
| 	m_scopes(_scopes), | ||||
| 	m_evmVersion(_evmVersion), | ||||
| 	m_errorReporter(_errorReporter), | ||||
| 	m_globalContext(_globalContext) | ||||
| { | ||||
| @ -324,7 +326,7 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res | ||||
| 	{ | ||||
| 		if (m_scopes.count(&_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/ASTVisitor.h> | ||||
| 
 | ||||
| #include <liblangutil/EVMVersion.h> | ||||
| 
 | ||||
| #include <boost/noncopyable.hpp> | ||||
| 
 | ||||
| #include <list> | ||||
| @ -55,6 +57,7 @@ public: | ||||
| 	/// are filled during the lifetime of this object.
 | ||||
| 	NameAndTypeResolver( | ||||
| 		GlobalContext& _globalContext, | ||||
| 		langutil::EVMVersion _evmVersion, | ||||
| 		std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes, | ||||
| 		langutil::ErrorReporter& _errorReporter | ||||
| 	); | ||||
| @ -130,6 +133,7 @@ private: | ||||
| 	/// Aliases (for example `import "x" as y;`) create multiple pointers to the same scope.
 | ||||
| 	std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes; | ||||
| 
 | ||||
| 	langutil::EVMVersion m_evmVersion; | ||||
| 	DeclarationContainer* m_currentScope = nullptr; | ||||
| 	langutil::ErrorReporter& m_errorReporter; | ||||
| 	GlobalContext& m_globalContext; | ||||
|  | ||||
| @ -350,7 +350,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly) | ||||
| 	yul::AsmAnalyzer( | ||||
| 		analysisInfo, | ||||
| 		errorsIgnored, | ||||
| 		yul::EVMDialect::strictAssemblyForEVM(EVMVersion{}), | ||||
| 		yul::EVMDialect::strictAssemblyForEVM(m_evmVersion), | ||||
| 		resolver | ||||
| 	).analyze(_inlineAssembly.operations()); | ||||
| 	return false; | ||||
|  | ||||
| @ -24,6 +24,7 @@ | ||||
| 
 | ||||
| #include <libsolidity/ast/ASTVisitor.h> | ||||
| #include <libsolidity/ast/ASTAnnotations.h> | ||||
| #include <liblangutil/EVMVersion.h> | ||||
| 
 | ||||
| #include <boost/noncopyable.hpp> | ||||
| #include <list> | ||||
| @ -52,10 +53,12 @@ public: | ||||
| 	ReferencesResolver( | ||||
| 		langutil::ErrorReporter& _errorReporter, | ||||
| 		NameAndTypeResolver& _resolver, | ||||
| 		langutil::EVMVersion _evmVersion, | ||||
| 		bool _resolveInsideCode = false | ||||
| 	): | ||||
| 		m_errorReporter(_errorReporter), | ||||
| 		m_resolver(_resolver), | ||||
| 		m_evmVersion(_evmVersion), | ||||
| 		m_resolveInsideCode(_resolveInsideCode) | ||||
| 	{} | ||||
| 
 | ||||
| @ -99,6 +102,7 @@ private: | ||||
| 
 | ||||
| 	langutil::ErrorReporter& m_errorReporter; | ||||
| 	NameAndTypeResolver& m_resolver; | ||||
| 	langutil::EVMVersion m_evmVersion; | ||||
| 	/// Stack of return parameters.
 | ||||
| 	std::vector<ParameterList const*> m_returnParameters; | ||||
| 	bool const m_resolveInsideCode; | ||||
|  | ||||
| @ -457,6 +457,9 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) | ||||
| 	TypePointer varType = _variable.annotation().type; | ||||
| 	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()) | ||||
| 		expectType(*_variable.value(), *varType); | ||||
| 	if (_variable.isConstant()) | ||||
| @ -2633,12 +2636,30 @@ bool TypeChecker::visit(Identifier const& _identifier) | ||||
| 				if (functionType->canTakeArguments(*annotation.arguments)) | ||||
| 					candidates.push_back(declaration); | ||||
| 			} | ||||
| 			if (candidates.empty()) | ||||
| 				m_errorReporter.fatalTypeError(_identifier.location(), "No matching declaration found after argument-dependent lookup."); | ||||
| 			else if (candidates.size() == 1) | ||||
| 			if (candidates.size() == 1) | ||||
| 				annotation.referencedDeclaration = candidates.front(); | ||||
| 			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( | ||||
|  | ||||
| @ -3411,6 +3411,15 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current | ||||
| 	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) | ||||
| { | ||||
| 	TypePointers params; | ||||
|  | ||||
| @ -1317,6 +1317,7 @@ public: | ||||
| 	std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; } | ||||
| 	MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; | ||||
| 
 | ||||
| 	BoolResult isExplicitlyConvertibleTo(Type const& _convertTo) const override; | ||||
| private: | ||||
| 	TypePointer m_actualType; | ||||
| }; | ||||
|  | ||||
| @ -475,7 +475,22 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) | ||||
| 	{ | ||||
| 		solAssert(_functionCall.arguments().size() == 1, ""); | ||||
| 		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; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -428,15 +428,20 @@ void BMC::inlineFunctionCall(FunctionCall const& _funCall) | ||||
| 		auto const& funType = dynamic_cast<FunctionType const*>(calledExpr->annotation().type); | ||||
| 		solAssert(funType, ""); | ||||
| 
 | ||||
| 		auto const& functionParams = funDef->parameters(); | ||||
| 		auto const& arguments = _funCall.arguments(); | ||||
| 		unsigned firstParam = 0; | ||||
| 		if (funType->bound()) | ||||
| 		{ | ||||
| 			auto const& boundFunction = dynamic_cast<MemberAccess const*>(calledExpr); | ||||
| 			solAssert(boundFunction, ""); | ||||
| 			funArgs.push_back(expr(boundFunction->expression())); | ||||
| 			funArgs.push_back(expr(boundFunction->expression(), functionParams.front()->type())); | ||||
| 			firstParam = 1; | ||||
| 		} | ||||
| 
 | ||||
| 		for (auto arg: _funCall.arguments()) | ||||
| 			funArgs.push_back(expr(*arg)); | ||||
| 		solAssert((arguments.size() + firstParam) == functionParams.size(), ""); | ||||
| 		for (unsigned i = 0; i < arguments.size(); ++i) | ||||
| 			funArgs.push_back(expr(*arguments.at(i), functionParams.at(i + firstParam)->type())); | ||||
| 		initializeFunctionCallParameters(*funDef, funArgs); | ||||
| 
 | ||||
| 		// 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); | ||||
| 	vector<smt::SortPointer> varSorts; | ||||
| 	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>( | ||||
| 		m_stateSorts + varSorts, | ||||
| 		boolSort | ||||
| @ -526,7 +532,13 @@ smt::SortPointer CHC::sort(ASTNode const* _node) | ||||
| 	auto boolSort = make_shared<smt::Sort>(smt::Kind::Bool); | ||||
| 	vector<smt::SortPointer> varSorts; | ||||
| 	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>( | ||||
| 		fSort->domain + varSorts, | ||||
| 		boolSort | ||||
| @ -540,7 +552,7 @@ unique_ptr<smt::SymbolicFunctionVariable> CHC::createSymbolicBlock(smt::SortPoin | ||||
| 		_name, | ||||
| 		m_context | ||||
| 	); | ||||
| 	m_interface->registerRelation(block->currentValue()); | ||||
| 	m_interface->registerRelation(block->currentFunctionValue()); | ||||
| 	return block; | ||||
| } | ||||
| 
 | ||||
| @ -572,7 +584,7 @@ smt::Expression CHC::error() | ||||
| 
 | ||||
| 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) | ||||
| @ -589,7 +601,7 @@ void CHC::createErrorBlock() | ||||
| { | ||||
| 	solAssert(m_errorPredicate, ""); | ||||
| 	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) | ||||
|  | ||||
| @ -154,15 +154,15 @@ private: | ||||
| 	//@{
 | ||||
| 	/// Constructor predicate.
 | ||||
| 	/// Default constructor sets state vars to 0.
 | ||||
| 	std::unique_ptr<smt::SymbolicVariable> m_constructorPredicate; | ||||
| 	std::unique_ptr<smt::SymbolicFunctionVariable> m_constructorPredicate; | ||||
| 
 | ||||
| 	/// Artificial Interface predicate.
 | ||||
| 	/// Single entry block for all functions.
 | ||||
| 	std::unique_ptr<smt::SymbolicVariable> m_interfacePredicate; | ||||
| 	std::unique_ptr<smt::SymbolicFunctionVariable> m_interfacePredicate; | ||||
| 
 | ||||
| 	/// Artificial Error predicate.
 | ||||
| 	/// Single error block for all assertions.
 | ||||
| 	std::unique_ptr<smt::SymbolicVariable> m_errorPredicate; | ||||
| 	std::unique_ptr<smt::SymbolicFunctionVariable> m_errorPredicate; | ||||
| 	//@}
 | ||||
| 
 | ||||
| 	/// Variables.
 | ||||
|  | ||||
| @ -136,9 +136,13 @@ void SMTEncoder::visitFunctionOrModifier() | ||||
| 			*modifierInvocation->name()->annotation().referencedDeclaration | ||||
| 		); | ||||
| 		vector<smt::Expression> modifierArgsExpr; | ||||
| 		if (modifierInvocation->arguments()) | ||||
| 			for (auto arg: *modifierInvocation->arguments()) | ||||
| 				modifierArgsExpr.push_back(expr(*arg)); | ||||
| 		if (auto const* arguments = modifierInvocation->arguments()) | ||||
| 		{ | ||||
| 			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); | ||||
| 		pushCallStack({&modifierDef, modifierInvocation.get()}); | ||||
| 		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.
 | ||||
| 	} | ||||
| 	else if (_identifier.annotation().type->category() == Type::Category::Function) | ||||
| 		visitFunctionIdentifier(_identifier); | ||||
| 	else if (auto decl = identifierToVariable(_identifier)) | ||||
| 		defineExpr(_identifier, currentValue(*decl)); | ||||
| 	else if (_identifier.annotation().type->category() == Type::Category::Function) | ||||
| 		visitFunctionIdentifier(_identifier); | ||||
| 	else if (_identifier.name() == "now") | ||||
| 		defineGlobalVariable(_identifier.name(), _identifier); | ||||
| 	else if (_identifier.name() == "this") | ||||
| @ -699,7 +703,7 @@ void SMTEncoder::endVisit(Return const& _return) | ||||
| 			} | ||||
| 		} | ||||
| 		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) | ||||
| { | ||||
| 	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); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,6 +19,7 @@ | ||||
| 
 | ||||
| #include <libsolidity/ast/TypeProvider.h> | ||||
| #include <libsolidity/ast/Types.h> | ||||
| #include <libdevcore/CommonData.h> | ||||
| #include <memory> | ||||
| 
 | ||||
| using namespace std; | ||||
| @ -139,7 +140,28 @@ pair<bool, shared_ptr<SymbolicVariable>> newSymbolicVariable( | ||||
| 	else if (isBool(_type.category())) | ||||
| 		var = make_shared<SymbolicBoolVariable>(type, _uniqueName, _context); | ||||
| 	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())) | ||||
| 		var = make_shared<SymbolicIntVariable>(type, type, _uniqueName, _context); | ||||
| 	else if (isFixedBytes(_type.category())) | ||||
|  | ||||
| @ -19,7 +19,6 @@ | ||||
| 
 | ||||
| #include <libsolidity/formal/SymbolicTypes.h> | ||||
| #include <libsolidity/ast/AST.h> | ||||
| #include <libsolidity/ast/TypeProvider.h> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace dev; | ||||
| @ -153,16 +152,38 @@ SymbolicFunctionVariable::SymbolicFunctionVariable( | ||||
| 	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() | ||||
| { | ||||
| 	++(*m_ssa); | ||||
| 	resetDeclaration(); | ||||
| 	return currentValue(); | ||||
| 	m_abstract.increaseIndex(); | ||||
| 	return m_abstract.currentValue(); | ||||
| } | ||||
| 
 | ||||
| Expression SymbolicFunctionVariable::operator()(vector<Expression> _arguments) const | ||||
| @ -170,6 +191,11 @@ Expression SymbolicFunctionVariable::operator()(vector<Expression> _arguments) c | ||||
| 	return m_declaration(_arguments); | ||||
| } | ||||
| 
 | ||||
| void SymbolicFunctionVariable::resetDeclaration() | ||||
| { | ||||
| 	m_declaration = m_context.newVariable(currentName(), m_sort); | ||||
| } | ||||
| 
 | ||||
| SymbolicMappingVariable::SymbolicMappingVariable( | ||||
| 	solidity::TypePointer _type, | ||||
| 	string _uniqueName, | ||||
|  | ||||
| @ -20,6 +20,7 @@ | ||||
| #include <libsolidity/formal/SolverInterface.h> | ||||
| #include <libsolidity/formal/SSAVariable.h> | ||||
| #include <libsolidity/ast/Types.h> | ||||
| #include <libsolidity/ast/TypeProvider.h> | ||||
| #include <memory> | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
| @ -154,8 +160,20 @@ public: | ||||
| 		EncodingContext& _context | ||||
| 	); | ||||
| 
 | ||||
| 	Expression increaseIndex(); | ||||
| 	Expression operator()(std::vector<Expression> _arguments) const; | ||||
| 	Expression currentValue(solidity::TypePointer const& _targetType = TypePointer{}) const override; | ||||
| 
 | ||||
| 	// 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: | ||||
| 	/// Creates a new function declaration.
 | ||||
| @ -163,6 +181,14 @@ private: | ||||
| 
 | ||||
| 	/// Stores the current function 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/Natspec.h> | ||||
| #include <libsolidity/interface/GasEstimator.h> | ||||
| #include <libsolidity/interface/StorageLayout.h> | ||||
| #include <libsolidity/interface/Version.h> | ||||
| #include <libsolidity/parsing/Parser.h> | ||||
| 
 | ||||
| @ -286,7 +287,7 @@ bool CompilerStack::analyze() | ||||
| 				noErrors = false; | ||||
| 
 | ||||
| 		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) | ||||
| 			if (!resolver.registerDeclarations(*source->ast)) | ||||
| 				return false; | ||||
| @ -684,6 +685,28 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const | ||||
| 	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 | ||||
| { | ||||
| 	if (m_stackState < AnalysisPerformed) | ||||
|  | ||||
| @ -287,6 +287,10 @@ public: | ||||
| 	/// Prerequisite: Successful call to parse or compile.
 | ||||
| 	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.
 | ||||
| 	/// Prerequisite: Successful call to parse or compile.
 | ||||
| 	Json::Value const& natspecUser(std::string const& _contractName) const; | ||||
| @ -334,6 +338,7 @@ private: | ||||
| 		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<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> devDocumentation; | ||||
| 		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.
 | ||||
| 	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.
 | ||||
| 	/// 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; | ||||
|  | ||||
| @ -927,10 +927,12 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting | ||||
| 		string file = contractName.substr(0, colon); | ||||
| 		string name = contractName.substr(colon + 1); | ||||
| 
 | ||||
| 		// ABI, documentation and metadata
 | ||||
| 		// ABI, storage layout, documentation and metadata
 | ||||
| 		Json::Value contractData(Json::objectValue); | ||||
| 		if (isArtifactRequested(_inputsAndSettings.outputSelection, file, name, "abi", wildcardMatchesExperimental)) | ||||
| 			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)) | ||||
| 			contractData["metadata"] = compilerStack.metadata(contractName); | ||||
| 		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", | ||||
|         "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 { | ||||
|     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 f1(uint[] memory c, test d) public pure returns (uint[] memory e) {  } | ||||
|     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, X d) public pure returns (uint[] memory e) {  } | ||||
| } | ||||
| // ---- | ||||
| //     :X | ||||
| // [] | ||||
| // | ||||
| // | ||||
| //     :test | ||||
| // [ | ||||
| //   { | ||||
| @ -15,9 +20,9 @@ library test { | ||||
| //         "type": "uint256[]" | ||||
| //       }, | ||||
| //       { | ||||
| //         "internalType": "library test", | ||||
| //         "internalType": "contract X", | ||||
| //         "name": "d", | ||||
| //         "type": "test" | ||||
| //         "type": "X" | ||||
| //       } | ||||
| //     ], | ||||
| //     "name": "f1", | ||||
|  | ||||
| @ -64,7 +64,7 @@ eth::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode) | ||||
| 
 | ||||
| 	map<ASTNode const*, shared_ptr<DeclarationContainer>> scopes; | ||||
| 	GlobalContext globalContext; | ||||
| 	NameAndTypeResolver resolver(globalContext, scopes, errorReporter); | ||||
| 	NameAndTypeResolver resolver(globalContext, dev::test::Options::get().evmVersion(), scopes, errorReporter); | ||||
| 	solAssert(Error::containsOnlyWarnings(errorReporter.errors()), ""); | ||||
| 	resolver.registerDeclarations(*sourceUnit); | ||||
| 	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) | ||||
| 			test.reset(); | ||||
| 
 | ||||
| 		map<string, dev::test::Address> libraries; | ||||
| 
 | ||||
| 		bool constructed = false; | ||||
| 
 | ||||
| 		for (auto& test: m_tests) | ||||
| 		{ | ||||
| 			if (&test == &m_tests.front()) | ||||
| 				if (test.call().isConstructor) | ||||
| 					deploy("", test.call().value, test.call().arguments.rawBytes()); | ||||
| 				else | ||||
| 					soltestAssert(deploy("", 0, bytes()), "Failed to deploy contract."); | ||||
| 			if (constructed) | ||||
| 			{ | ||||
| 				soltestAssert(!test.call().isLibrary, "Libraries have to be deployed before any other call."); | ||||
| 				soltestAssert(!test.call().isConstructor, "Constructor has to be the first function call expect for library deployments."); | ||||
| 			} | ||||
| 			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 | ||||
| 				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) | ||||
| 			{ | ||||
| @ -171,8 +190,8 @@ void SemanticTest::parseExpectations(istream& _stream) | ||||
| 	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; | ||||
| } | ||||
|  | ||||
| @ -60,7 +60,7 @@ public: | ||||
| 
 | ||||
| 	/// Compiles and deploys currently held source.
 | ||||
| 	/// 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: | ||||
| 	std::string m_source; | ||||
|  | ||||
| @ -118,7 +118,7 @@ bytes compileFirstExpression( | ||||
| 	ErrorReporter errorReporter(errors); | ||||
| 	GlobalContext globalContext; | ||||
| 	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); | ||||
| 
 | ||||
| 	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; | ||||
| 		require(true); | ||||
| 	} | ||||
| 	/* Not properly supported by test system yet | ||||
| 	function f2(bool a) public pure returns (bool x) { | ||||
| 		x = a; | ||||
| 		string memory message; | ||||
| 		message = "fancy 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): false -> FAILURE | ||||
| // fail() -> FAILURE | ||||
| // 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 { | ||||
|     function f() pure external { | ||||
|     function f() pure external returns (uint id) { | ||||
|         assembly { | ||||
|             pop(chainid()) | ||||
|             id := chainid() | ||||
|         } | ||||
|     } | ||||
|     function g() view external { | ||||
|     function g() view external returns (uint sb) { | ||||
|         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. | ||||
|  | ||||
| @ -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)       \ | ||||
| 	/* special keywords */         \ | ||||
| 	K(Left, "left", 0)             \ | ||||
| 	K(Library, "library", 0)       \ | ||||
| 	K(Right, "right", 0)           \ | ||||
| 	K(Failure, "FAILURE", 0)       \ | ||||
| 
 | ||||
| @ -268,6 +269,8 @@ struct FunctionCall | ||||
| 	/// Marks this function call as "short-handed", meaning
 | ||||
| 	/// no `->` declared.
 | ||||
| 	bool omitsArrow = true; | ||||
| 	/// Marks a library deployment call.
 | ||||
| 	bool isLibrary = false; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -75,44 +75,56 @@ vector<dev::solidity::test::FunctionCall> TestFileParser::parseFunctionCalls(siz | ||||
| 
 | ||||
| 				try | ||||
| 				{ | ||||
| 					tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature(); | ||||
| 					if (accept(Token::Comma, true)) | ||||
| 						call.value = parseFunctionCallValue(); | ||||
| 					if (accept(Token::Colon, true)) | ||||
| 						call.arguments = parseFunctionCallArguments(); | ||||
| 
 | ||||
| 					if (accept(Token::Newline, true)) | ||||
| 					if (accept(Token::Library, 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++; | ||||
| 						expect(Token::Colon); | ||||
| 						call.signature = m_scanner.currentLiteral(); | ||||
| 						expect(Token::Identifier); | ||||
| 						call.isLibrary = true; | ||||
| 						call.expectations.failure = false; | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						call.expectations.failure = false; | ||||
| 						call.displayMode = FunctionCall::DisplayMode::SingleLine; | ||||
| 						tie(call.signature, call.useCallWithoutSignature) = parseFunctionSignature(); | ||||
| 						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)); | ||||
| 				} | ||||
| 				catch (Error const& _e) | ||||
| @ -456,6 +468,7 @@ void TestFileParser::Scanner::scanNextToken() | ||||
| 		if (_literal == "false") return TokenDesc{Token::Boolean, _literal}; | ||||
| 		if (_literal == "ether") return TokenDesc{Token::Ether, _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 == "hex") return TokenDesc{Token::Hex, _literal}; | ||||
| 		if (_literal == "FAILURE") return TokenDesc{Token::Failure, _literal}; | ||||
|  | ||||
| @ -57,7 +57,9 @@ void testFunctionCall( | ||||
| 		u256 _value = 0, | ||||
| 		string _argumentComment = "", | ||||
| 		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); | ||||
| @ -79,6 +81,9 @@ void testFunctionCall( | ||||
| 			++index; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	BOOST_REQUIRE_EQUAL(_call.isConstructor, _isConstructor); | ||||
| 	BOOST_REQUIRE_EQUAL(_call.isLibrary, _isLibrary); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE(TestFileParserTest) | ||||
| @ -883,6 +888,51 @@ BOOST_AUTO_TEST_CASE(call_unexpected_character) | ||||
| 	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() | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -55,6 +55,12 @@ string TestFunctionCall::format( | ||||
| 		string newline = formatToken(Token::Newline); | ||||
| 		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.
 | ||||
| 		stream << _linePrefix << newline << ws << m_call.signature; | ||||
| 		if (m_call.value > u256(0)) | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user