void ClassVariable::onParseRecur(AnalysisResultConstRawPtr ar, FileScopeRawPtr fs, ClassScopePtr scope) { ModifierExpressionPtr modifiers = scope->setModifiers(m_modifiers); if (m_modifiers->isAbstract()) { m_modifiers->parseTimeFatal(fs, Compiler::InvalidAttribute, "Properties cannot be declared abstract"); } if (m_modifiers->isFinal()) { m_modifiers->parseTimeFatal(fs, Compiler::InvalidAttribute, "Properties cannot be declared final"); } if (!m_modifiers->isStatic() && scope->isStaticUtil()) { m_modifiers->parseTimeFatal( fs, Compiler::InvalidAttribute, "Class %s contains non-static property declaration and " "therefore cannot be declared 'abstract final'", scope->getOriginalName().c_str() ); } if ((m_modifiers->isExplicitlyPublic() + m_modifiers->isProtected() + m_modifiers->isPrivate()) > 1) { m_modifiers->parseTimeFatal( fs, Compiler::InvalidAttribute, "%s: properties of %s", Strings::PICK_ACCESS_MODIFIER, scope->getOriginalName().c_str() ); } for (int i = 0; i < m_declaration->getCount(); i++) { VariableTablePtr variables = scope->getVariables(); ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { auto assignment = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr var = assignment->getVariable(); const auto& name = dynamic_pointer_cast<SimpleVariable>(var)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(fs, Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { assignment->onParseRecur(ar, fs, scope); } } else { const std::string &name = dynamic_pointer_cast<SimpleVariable>(exp)->getName(); if (variables->isPresent(name)) { exp->parseTimeFatal(fs, Compiler::DeclaredVariableTwice, "Cannot redeclare %s::$%s", scope->getOriginalName().c_str(), name.c_str()); } else { variables->add(name, false, ar, exp, m_modifiers); } } } scope->setModifiers(modifiers); }
void MethodStatement::onParseRecur(AnalysisResultConstRawPtr ar, FileScopeRawPtr fileScope, ClassScopePtr classScope) { checkParameters(fileScope); FunctionScopeRawPtr funcScope = getFunctionScope(); funcScope->setOuterScope(classScope); const bool isNative = funcScope->isNative(); if (m_modifiers) { if ((m_modifiers->isExplicitlyPublic() + m_modifiers->isProtected() + m_modifiers->isPrivate()) > 1) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::PICK_ACCESS_MODIFIER ); } if (m_modifiers->hasDuplicates()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::PICK_ACCESS_MODIFIER); } if (classScope->isInterface()) { if (m_modifiers->isProtected() || m_modifiers->isPrivate() || m_modifiers->isAbstract() || m_modifiers->isFinal() || isNative) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Access type for interface method %s::%s() must be omitted", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isAsync()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::ASYNC_WITHOUT_BODY, "interface", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } if (getStmts()) { getStmts()->parseTimeFatal( fileScope, Compiler::InvalidMethodDefinition, "Interface method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } if (m_modifiers->isAbstract()) { if (!Option::WholeProgram && funcScope->userAttributes().count("__Memoize")) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Abstract method %s::%s cannot be memoized", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isPrivate() || m_modifiers->isFinal() || isNative) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Cannot declare abstract method %s::%s() %s", classScope->getOriginalName().c_str(), getOriginalName().c_str(), m_modifiers->isPrivate() ? "private" : (m_modifiers->isFinal() ? "final" : "native")); } if (!classScope->isInterface() && !classScope->isAbstract()) { /* note that classScope->isAbstract() returns true for traits */ m_modifiers->parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Class %s contains abstract method %s and " "must therefore be declared abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (getStmts()) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Abstract method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } if (m_modifiers->isAsync()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, Strings::ASYNC_WITHOUT_BODY, "abstract", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } } if (!m_modifiers->isStatic() && classScope->isStaticUtil()) { m_modifiers->parseTimeFatal( fileScope, Compiler::InvalidAttribute, "Class %s contains non-static method %s and " "therefore cannot be declared 'abstract final'", classScope->getOriginalName().c_str(), getOriginalName().c_str() ); } if (isNative) { if (getStmts()) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method %s::%s() cannot contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } auto is_ctordtor = isNamed("__construct") || isNamed("__destruct"); if (!m_retTypeAnnotation && !is_ctordtor) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method %s::%s() must have a return type hint", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } else if (m_retTypeAnnotation && is_ctordtor && (m_retTypeAnnotation->dataType() != KindOfNull)) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method %s::%s() must return void", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } } } if ((!m_modifiers || !m_modifiers->isAbstract()) && !getStmts() && !classScope->isInterface() && !isNative) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Non-abstract method %s::%s() must contain body", classScope->getOriginalName().c_str(), getOriginalName().c_str()); } classScope->addFunction(ar, fileScope, funcScope); setSpecialMethod(fileScope, classScope); if (RuntimeOption::DynamicInvokeFunctions.count(getOriginalFullName())) { funcScope->setDynamicInvoke(); } if (m_params) { auto nParams = m_params->getCount(); for (int i = 0; i < nParams; i++) { auto param = dynamic_pointer_cast<ParameterExpression>((*m_params)[i]); param->parseHandler(fileScope, classScope); // Variadic capture params don't need types because they'll // be treated as Arrays as far as HNI is concerned. if (isNative && !param->hasUserType() && !param->isVariadic()) { parseTimeFatal(fileScope, Compiler::InvalidAttribute, "Native method calls must have type hints on all args"); } } } FunctionScope::RecordFunctionInfo(m_originalName, funcScope); }