bool DeclarationAnalyzer::verifyProtocolFunction(const TypePtr& type, const TypePtr& protocol, const FunctionSymbolPtr& expected, bool supressError) { std::vector<SymbolPtr> results; int filter = FilterLookupInExtension | FilterRecursive; if(expected->hasFlags(SymbolFlagStatic)) filter |= FilterStaticMember; semanticAnalyzer->getMethodsFromType(type, expected->getName(), (MemberFilter)filter, results); TypePtr expectedType = expected->getType(); assert(expectedType != nullptr); //verify if they're the same type bool found = false; for(const SymbolPtr& func : results) { if(checkTypeConform(type, expectedType, func->getType())) { found = true; break; } } if(!found) { if(!supressError) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_FUNCTION_3, type->getName(), protocol->getName(), expected->getName()); } return false; } return true; }
void FunctionAnalyzer::visitFunction(const FunctionDefPtr& node) { if(node->hasModifier(DeclarationModifiers::_Generated)) return; //visit implementation FunctionSymbolPtr func = static_pointer_cast<SymboledFunction>(node)->symbol; if(func->getDeclaringType() && func->getDeclaringType()->getCategory() == Type::Protocol) return;//do not check implementation if it's defined as protocol function assert(func != nullptr); SCOPED_SET(ctx->currentFunction, func->getType()); node->getBody()->accept(semanticAnalyzer); if(!Type::equals(func->getType()->getReturnType(), symbolRegistry->getGlobalScope()->Void())) { //check return in all branches ReturnStatementValidator validator(ctx); node->getBody()->accept(&validator); NodePtr refNode = validator.getRefNode() ? validator.getRefNode() : node; ReturnCoverResult result = validator.getResult(); if (result & ReturnCoverDeadcode) { this->warning(refNode, Errors::W_CODE_AFTER_A_WILL_NEVER_BE_EXECUTED_1, L"return"); return; } switch (result) { case ReturnCoverNoResult: case ReturnCoverUnmatched: case ReturnCoverPartial: error(refNode, Errors::E_MISSING_RETURN_IN_A_FUNCTION_EXPECTED_TO_RETURN_A_1, func->getType()->getReturnType()->toString()); return; default: break; } } }
void DeclarationAnalyzer::verifyProtocolFunction(const TypePtr& type, const TypePtr& protocol, const FunctionSymbolPtr& expected) { SymbolPtr sym = type->getMember(expected->getName()); TypePtr expectedType = expected->getType(); assert(expectedType != nullptr); if(!sym) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_FUNCTION_3, type->getName(), protocol->getName(), expected->getName()); return; } else if(const FunctionSymbolPtr& func = std::dynamic_pointer_cast<FunctionSymbol>(sym)) { //verify if they're the same type TypePtr funcType = func->getType(); assert(funcType != nullptr); if(!Type::equals(funcType, expectedType)) { error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_FUNCTION_3, type->getName(), protocol->getName(), expected->getName()); } return; } else if(FunctionOverloadedSymbolPtr funcs = std::dynamic_pointer_cast<FunctionOverloadedSymbol>(sym)) { //verify if they're the same type bool found = false; for(const FunctionSymbolPtr& func : *funcs) { if(Type::equals(func->getType(), expectedType)) { found = true; break; } } if(!found) error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_FUNCTION_3, type->getName(), protocol->getName(), expected->getName()); return; } else if(SymbolPlaceHolderPtr prop = std::dynamic_pointer_cast<SymbolPlaceHolder>(sym)) { } error(type->getReference(), Errors::E_TYPE_DOES_NOT_CONFORM_TO_PROTOCOL_UNIMPLEMENTED_FUNCTION_3, type->getName(), protocol->getName(), expected->getName()); }
void FunctionAnalyzer::visitInit(const InitializerDefPtr& node) { FunctionSymbolPtr init = static_pointer_cast<SymboledInit>(node)->symbol; TypePtr funcType = init->getType(); SCOPED_SET(ctx->currentFunction, funcType); { InitializationTracer tracer(nullptr, InitializationTracer::Sequence); SCOPED_SET(ctx->currentInitializationTracer, &tracer); node->getBody()->accept(semanticAnalyzer); //check if some stored property is not initialized for(const SymbolPtr& storedProp : ctx->currentType->getDeclaredStoredProperties()) { if(!storedProp->hasFlags(SymbolFlagInitialized)) { error(node, Errors::E_PROPERTY_A_NOT_INITIALIZED, L"self." + storedProp->getName()); return; } } } if(node->hasModifier(DeclarationModifiers::Convenience)) { //convenience initializer must call designated initializer in all paths InitializerValidator validator(ctx, this); node->getBody()->accept(&validator); NodePtr refNode = validator.getRefNode() ? validator.getRefNode() : node; if(validator.getResult() & InitializerCoverMultiple) { error(refNode, Errors::E_SELF_INIT_CALLED_MULTIPLE_TIMES_IN_INITIALIZER); return; } switch(validator.getResult()) { case InitializerCoverNoResult: case InitializerCoverUnmatched: case InitializerCoverPartial: error(refNode, Errors::E_SELF_INIT_ISNT_CALLED_ON_ALL_PATHS_IN_DELEGATING_INITIALIZER); return; default: break; } } else { //designated initializer must call designated initializer if parent type has customized initializer bool hasCustomizedInitializer = false; if(ctx->currentType->getParentType()) { FunctionOverloadedSymbolPtr inits = ctx->currentType->getDeclaredInitializer(); if(inits) { for(const FunctionSymbolPtr& init : *inits) { if(!init->getType()->getParameters().empty()) { hasCustomizedInitializer = true; break; } } } } if(hasCustomizedInitializer) { InitializerValidator validator(ctx, this); node->getBody()->accept(&validator); NodePtr refNode = validator.getRefNode() ? validator.getRefNode() : node; if(validator.getResult() & InitializerCoverMultiple) { error(refNode, Errors::E_SUPER_INIT_CALLED_MULTIPLE_TIMES_IN_INITIALIZER); return; } switch(validator.getResult()) { case InitializerCoverNoResult: case InitializerCoverUnmatched: case InitializerCoverPartial: error(refNode, Errors::E_SUPER_INIT_ISNT_CALLED_BEFORE_RETURNING_FROM_INITIALIZER); return; default: break; } } } }