diff options
author | chriseth <chris@ethereum.org> | 2018-11-30 00:58:15 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2018-11-30 23:30:19 +0800 |
commit | 2c2c976697d22400d37f3b26064b6b1f6fc91dba (patch) | |
tree | 45e5b0a94054e51cff3f95d5c8464cc39ad6323d /libsolidity/analysis/ContractLevelChecker.cpp | |
parent | 57a62429c9d0be4b3a8a9cc98fa7eb46a6015165 (diff) | |
download | dexon-solidity-2c2c976697d22400d37f3b26064b6b1f6fc91dba.tar.gz dexon-solidity-2c2c976697d22400d37f3b26064b6b1f6fc91dba.tar.zst dexon-solidity-2c2c976697d22400d37f3b26064b6b1f6fc91dba.zip |
Move base constructor argument checks.
Diffstat (limited to 'libsolidity/analysis/ContractLevelChecker.cpp')
-rw-r--r-- | libsolidity/analysis/ContractLevelChecker.cpp | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 74ac665f..f41e569f 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -39,6 +39,7 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract) checkContractDuplicateEvents(_contract); checkContractIllegalOverrides(_contract); checkContractAbstractFunctions(_contract); + checkContractBaseConstructorArguments(_contract); return Error::containsOnlyWarnings(m_errorReporter.errors()); } @@ -248,3 +249,93 @@ void ContractLevelChecker::checkContractAbstractFunctions(ContractDefinition con break; } } + + +void ContractLevelChecker::checkContractBaseConstructorArguments(ContractDefinition const& _contract) +{ + vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts; + + // Determine the arguments that are used for the base constructors. + for (ContractDefinition const* contract: bases) + { + if (FunctionDefinition const* constructor = contract->constructor()) + for (auto const& modifier: constructor->modifiers()) + if (auto baseContract = dynamic_cast<ContractDefinition const*>( + modifier->name()->annotation().referencedDeclaration + )) + { + if (modifier->arguments()) + { + if (baseContract->constructor()) + annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get()); + } + else + m_errorReporter.declarationError( + modifier->location(), + "Modifier-style base constructor call without arguments." + ); + } + + for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts()) + { + ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>( + base->name().annotation().referencedDeclaration + ); + solAssert(baseContract, ""); + + if (baseContract->constructor() && base->arguments() && !base->arguments()->empty()) + annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get()); + } + } + + // check that we get arguments for all base constructors that need it. + // If not mark the contract as abstract (not fully implemented) + for (ContractDefinition const* contract: bases) + if (FunctionDefinition const* constructor = contract->constructor()) + if (contract != &_contract && !constructor->parameters().empty()) + if (!_contract.annotation().baseConstructorArguments.count(constructor)) + _contract.annotation().unimplementedFunctions.push_back(constructor); +} + +void ContractLevelChecker::annotateBaseConstructorArguments( + ContractDefinition const& _currentContract, + FunctionDefinition const* _baseConstructor, + ASTNode const* _argumentNode +) +{ + solAssert(_baseConstructor, ""); + solAssert(_argumentNode, ""); + + auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert( + std::make_pair(_baseConstructor, _argumentNode) + ); + if (!insertionResult.second) + { + ASTNode const* previousNode = insertionResult.first->second; + + SourceLocation const* mainLocation = nullptr; + SecondarySourceLocation ssl; + + if ( + _currentContract.location().contains(previousNode->location()) || + _currentContract.location().contains(_argumentNode->location()) + ) + { + mainLocation = &previousNode->location(); + ssl.append("Second constructor call is here:", _argumentNode->location()); + } + else + { + mainLocation = &_currentContract.location(); + ssl.append("First constructor call is here: ", _argumentNode->location()); + ssl.append("Second constructor call is here: ", previousNode->location()); + } + + m_errorReporter.declarationError( + *mainLocation, + ssl, + "Base constructor arguments given twice." + ); + } + +} |