| 290 | } |
| 291 | |
| 292 | void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _contract) |
| 293 | { |
| 294 | // Collects functions, static variable getters and modifiers. If they |
| 295 | // override (unimplemented) base class ones, they are replaced. |
| 296 | std::set<OverrideProxy, OverrideProxy::CompareBySignature> proxies; |
| 297 | |
| 298 | auto registerProxy = [&proxies](OverrideProxy const& _overrideProxy) |
| 299 | { |
| 300 | // Overwrite an existing proxy, if it exists. |
| 301 | if (!_overrideProxy.unimplemented()) |
| 302 | proxies.erase(_overrideProxy); |
| 303 | |
| 304 | proxies.insert(_overrideProxy); |
| 305 | }; |
| 306 | |
| 307 | // Search from base to derived, collect all functions and modifiers and |
| 308 | // update proxies. |
| 309 | for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse) |
| 310 | { |
| 311 | for (VariableDeclaration const* v: contract->stateVariables()) |
| 312 | if (v->isPartOfExternalInterface()) |
| 313 | registerProxy(OverrideProxy(v)); |
| 314 | |
| 315 | for (FunctionDefinition const* function: contract->definedFunctions()) |
| 316 | if (!function->isConstructor()) |
| 317 | registerProxy(OverrideProxy(function)); |
| 318 | |
| 319 | for (ModifierDefinition const* modifier: contract->functionModifiers()) |
| 320 | registerProxy(OverrideProxy(modifier)); |
| 321 | } |
| 322 | |
| 323 | // Set to not fully implemented if at least one flag is false. |
| 324 | for (auto const& proxy: proxies) |
| 325 | if (proxy.unimplemented()) |
| 326 | _contract.annotation().unimplementedDeclarations->push_back(proxy.declaration()); |
| 327 | |
| 328 | if (_contract.abstract()) |
| 329 | { |
| 330 | if (_contract.contractKind() == ContractKind::Interface) |
| 331 | m_errorReporter.typeError(9348_error, _contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly."); |
| 332 | else if (_contract.contractKind() == ContractKind::Library) |
| 333 | m_errorReporter.typeError(9571_error, _contract.location(), "Libraries cannot be abstract."); |
| 334 | else |
| 335 | solAssert(_contract.contractKind() == ContractKind::Contract, ""); |
| 336 | } |
| 337 | |
| 338 | // For libraries, we emit errors on function-level, so this is fine as long as we do |
| 339 | // not have inheritance for libraries. |
| 340 | if ( |
| 341 | _contract.contractKind() == ContractKind::Contract && |
| 342 | !_contract.abstract() && |
| 343 | !_contract.annotation().unimplementedDeclarations->empty() |
| 344 | ) |
| 345 | { |
| 346 | SecondarySourceLocation ssl; |
| 347 | for (auto declaration: *_contract.annotation().unimplementedDeclarations) |
| 348 | ssl.append("Missing implementation: ", declaration->location()); |
| 349 | m_errorReporter.typeError( |
nothing calls this directly
no test coverage detected