mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Parsing and type checking of libraries without inheritance.
This commit is contained in:
		
							parent
							
								
									c5b6d9d2a9
								
							
						
					
					
						commit
						337fde9d11
					
				| @ -103,6 +103,9 @@ void ContractDefinition::checkTypeRequirements() | ||||
| 			)); | ||||
| 		hashes.insert(hash); | ||||
| 	} | ||||
| 
 | ||||
| 	if (isLibrary()) | ||||
| 		checkLibraryRequirements(); | ||||
| } | ||||
| 
 | ||||
| map<FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions() const | ||||
| @ -332,6 +335,17 @@ void ContractDefinition::checkExternalTypeClashes() const | ||||
| 					)); | ||||
| } | ||||
| 
 | ||||
| void ContractDefinition::checkLibraryRequirements() const | ||||
| { | ||||
| 	solAssert(m_isLibrary, ""); | ||||
| 	if (!m_baseContracts.empty()) | ||||
| 		BOOST_THROW_EXCEPTION(createTypeError("Library is not allowed to inherit.")); | ||||
| 
 | ||||
| 	for (auto const& var: m_stateVariables) | ||||
| 		if (!var->isConstant()) | ||||
| 			BOOST_THROW_EXCEPTION(var->createTypeError("Library cannot have non-constant state variables")); | ||||
| } | ||||
| 
 | ||||
| vector<ASTPointer<EventDefinition>> const& ContractDefinition::interfaceEvents() const | ||||
| { | ||||
| 	if (!m_interfaceEvents) | ||||
| @ -449,6 +463,10 @@ void InheritanceSpecifier::checkTypeRequirements() | ||||
| 
 | ||||
| 	ContractDefinition const* base = dynamic_cast<ContractDefinition const*>(&m_baseName->referencedDeclaration()); | ||||
| 	solAssert(base, "Base contract not available."); | ||||
| 
 | ||||
| 	if (base->isLibrary()) | ||||
| 		BOOST_THROW_EXCEPTION(createTypeError("Libraries cannot be inherited from.")); | ||||
| 
 | ||||
| 	TypePointers parameterTypes = ContractType(*base).constructorType()->parameterTypes(); | ||||
| 	if (!m_arguments.empty() && parameterTypes.size() != m_arguments.size()) | ||||
| 		BOOST_THROW_EXCEPTION(createTypeError( | ||||
|  | ||||
| @ -215,7 +215,7 @@ protected: | ||||
| /// @}
 | ||||
| 
 | ||||
| /**
 | ||||
|  * Definition of a contract. This is the only AST nodes where child nodes are not visited in | ||||
|  * Definition of a contract or library. This is the only AST nodes where child nodes are not visited in | ||||
|  * document order. It first visits all struct declarations, then all variable declarations and | ||||
|  * finally all function declarations. | ||||
|  */ | ||||
| @ -232,7 +232,8 @@ public: | ||||
| 		std::vector<ASTPointer<VariableDeclaration>> const& _stateVariables, | ||||
| 		std::vector<ASTPointer<FunctionDefinition>> const& _definedFunctions, | ||||
| 		std::vector<ASTPointer<ModifierDefinition>> const& _functionModifiers, | ||||
| 		std::vector<ASTPointer<EventDefinition>> const& _events | ||||
| 		std::vector<ASTPointer<EventDefinition>> const& _events, | ||||
| 		bool _isLibrary | ||||
| 	): | ||||
| 		Declaration(_location, _name), | ||||
| 		Documented(_documentation), | ||||
| @ -243,7 +244,8 @@ public: | ||||
| 		m_stateVariables(_stateVariables), | ||||
| 		m_definedFunctions(_definedFunctions), | ||||
| 		m_functionModifiers(_functionModifiers), | ||||
| 		m_events(_events) | ||||
| 		m_events(_events), | ||||
| 		m_isLibrary(_isLibrary) | ||||
| 	{} | ||||
| 
 | ||||
| 	virtual void accept(ASTVisitor& _visitor) override; | ||||
| @ -257,6 +259,7 @@ public: | ||||
| 	std::vector<ASTPointer<FunctionDefinition>> const& definedFunctions() const { return m_definedFunctions; } | ||||
| 	std::vector<ASTPointer<EventDefinition>> const& events() const { return m_events; } | ||||
| 	std::vector<ASTPointer<EventDefinition>> const& interfaceEvents() const; | ||||
| 	bool isLibrary() const { return m_isLibrary; } | ||||
| 
 | ||||
| 	virtual TypePointer type(ContractDefinition const* m_currentContract) const override; | ||||
| 
 | ||||
| @ -297,6 +300,8 @@ private: | ||||
| 	/// Checks that different functions with external visibility end up having different
 | ||||
| 	/// external argument types (i.e. different signature).
 | ||||
| 	void checkExternalTypeClashes() const; | ||||
| 	/// Checks that all requirements for a library are fulfilled if this is a library.
 | ||||
| 	void checkLibraryRequirements() const; | ||||
| 
 | ||||
| 	std::vector<std::pair<FixedHash<4>, FunctionTypePointer>> const& interfaceFunctionList() const; | ||||
| 
 | ||||
| @ -307,6 +312,7 @@ private: | ||||
| 	std::vector<ASTPointer<FunctionDefinition>> m_definedFunctions; | ||||
| 	std::vector<ASTPointer<ModifierDefinition>> m_functionModifiers; | ||||
| 	std::vector<ASTPointer<EventDefinition>> m_events; | ||||
| 	bool m_isLibrary; | ||||
| 
 | ||||
| 	// parsed Natspec documentation of the contract.
 | ||||
| 	std::string m_userDocumentation; | ||||
|  | ||||
| @ -71,13 +71,14 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner) | ||||
| 	vector<ASTPointer<ASTNode>> nodes; | ||||
| 	while (m_scanner->currentToken() != Token::EOS) | ||||
| 	{ | ||||
| 		switch (m_scanner->currentToken()) | ||||
| 		switch (auto token = m_scanner->currentToken()) | ||||
| 		{ | ||||
| 		case Token::Import: | ||||
| 			nodes.push_back(parseImportDirective()); | ||||
| 			break; | ||||
| 		case Token::Contract: | ||||
| 			nodes.push_back(parseContractDefinition()); | ||||
| 		case Token::Library: | ||||
| 			nodes.push_back(parseContractDefinition(token == Token::Library)); | ||||
| 			break; | ||||
| 		default: | ||||
| 			BOOST_THROW_EXCEPTION(createParserError(std::string("Expected import directive or contract definition."))); | ||||
| @ -113,13 +114,13 @@ ASTPointer<ImportDirective> Parser::parseImportDirective() | ||||
| 	return nodeFactory.createNode<ImportDirective>(url); | ||||
| } | ||||
| 
 | ||||
| ASTPointer<ContractDefinition> Parser::parseContractDefinition() | ||||
| ASTPointer<ContractDefinition> Parser::parseContractDefinition(bool _isLibrary) | ||||
| { | ||||
| 	ASTNodeFactory nodeFactory(*this); | ||||
| 	ASTPointer<ASTString> docString; | ||||
| 	if (m_scanner->currentCommentLiteral() != "") | ||||
| 		docString = make_shared<ASTString>(m_scanner->currentCommentLiteral()); | ||||
| 	expectToken(Token::Contract); | ||||
| 	expectToken(_isLibrary ? Token::Library : Token::Contract); | ||||
| 	ASTPointer<ASTString> name = expectIdentifierToken(); | ||||
| 	vector<ASTPointer<InheritanceSpecifier>> baseContracts; | ||||
| 	vector<ASTPointer<StructDefinition>> structs; | ||||
| @ -177,7 +178,8 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition() | ||||
| 		stateVariables, | ||||
| 		functions, | ||||
| 		modifiers, | ||||
| 		events | ||||
| 		events, | ||||
| 		_isLibrary | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -61,15 +61,17 @@ private: | ||||
| 	///@{
 | ||||
| 	///@name Parsing functions for the AST nodes
 | ||||
| 	ASTPointer<ImportDirective> parseImportDirective(); | ||||
| 	ASTPointer<ContractDefinition> parseContractDefinition(); | ||||
| 	ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary); | ||||
| 	ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier(); | ||||
| 	Declaration::Visibility parseVisibilitySpecifier(Token::Value _token); | ||||
| 	ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName); | ||||
| 	ASTPointer<StructDefinition> parseStructDefinition(); | ||||
| 	ASTPointer<EnumDefinition> parseEnumDefinition(); | ||||
| 	ASTPointer<EnumValue> parseEnumValue(); | ||||
| 	ASTPointer<VariableDeclaration> parseVariableDeclaration(VarDeclParserOptions const& _options = VarDeclParserOptions(), | ||||
| 		ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>()); | ||||
| 	ASTPointer<VariableDeclaration> parseVariableDeclaration( | ||||
| 		VarDeclParserOptions const& _options = VarDeclParserOptions(), | ||||
| 		ASTPointer<TypeName> const& _lookAheadArrayType = ASTPointer<TypeName>() | ||||
| 	); | ||||
| 	ASTPointer<ModifierDefinition> parseModifierDefinition(); | ||||
| 	ASTPointer<EventDefinition> parseEventDefinition(); | ||||
| 	ASTPointer<ModifierInvocation> parseModifierInvocation(); | ||||
|  | ||||
| @ -160,6 +160,7 @@ namespace solidity | ||||
| 	K(Internal, "internal", 0)                                         \ | ||||
| 	K(Import, "import", 0)                                             \ | ||||
| 	K(Is, "is", 0)                                                     \ | ||||
| 	K(Library, "library", 0)                                           \ | ||||
| 	K(Mapping, "mapping", 0)                                           \ | ||||
| 	K(Memory, "memory", 0)                                             \ | ||||
| 	K(Modifier, "modifier", 0)                                         \ | ||||
| @ -305,7 +306,7 @@ namespace solidity | ||||
| 	/* Identifiers (not keywords or future reserved words). */         \ | ||||
| 	T(Identifier, NULL, 0)                                             \ | ||||
| 	\ | ||||
| 	/* Keywords reserved for future. use. */                           \ | ||||
| 	/* Keywords reserved for future use. */                            \ | ||||
| 	K(As, "as", 0)                                                     \ | ||||
| 	K(Case, "case", 0)                                                 \ | ||||
| 	K(Catch, "catch", 0)                                               \ | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| ContractDefinition = 'contract' Identifier | ||||
| ContractDefinition = ( 'contract' | 'library' ) Identifier | ||||
|                      ( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )? | ||||
|                      '{' ContractPart* '}' | ||||
| ContractPart = StateVariableDeclaration | StructDefinition | ModifierDefinition | FunctionDefinition | EnumDefinition | ||||
|  | ||||
| @ -2194,6 +2194,39 @@ BOOST_AUTO_TEST_CASE(string_bytes_conversion) | ||||
| 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(inheriting_from_library) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		library Lib {} | ||||
| 		contract Test is Lib {} | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(inheriting_library) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		contract Test {} | ||||
| 		library Lib is Test {} | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(library_having_variables) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		library Lib { uint x; } | ||||
| 	)"; | ||||
| 	BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(valid_library) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		library Lib { uint constant x = 9; } | ||||
| 	)"; | ||||
| 	BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract) | ||||
| { | ||||
|  | ||||
| @ -924,6 +924,16 @@ BOOST_AUTO_TEST_CASE(empty_comment) | ||||
| 	BOOST_CHECK_NO_THROW(parseText(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_CASE(library_simple) | ||||
| { | ||||
| 	char const* text = R"( | ||||
| 		library Lib { | ||||
| 			function f() { } | ||||
| 		} | ||||
| 	)"; | ||||
| 	BOOST_CHECK_NO_THROW(parseText(text)); | ||||
| } | ||||
| 
 | ||||
| BOOST_AUTO_TEST_SUITE_END() | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user