void StatementList::analyzeProgramImpl(AnalysisResultPtr ar) { m_included = true; for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; // effect testing if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (!stmt->hasEffect() && !stmt->is(Statement::KindOfStatementList)) { Compiler::Error(Compiler::StatementHasNoEffect, stmt); } if (stmt->is(Statement::KindOfExpStatement)) { static_pointer_cast<ExpStatement>(stmt)->analyzeShortCircuit(ar); } } bool scopeStmt = stmt->is(Statement::KindOfFunctionStatement) || stmt->is(Statement::KindOfClassStatement) || stmt->is(Statement::KindOfInterfaceStatement); if (ar->getPhase() != AnalysisResult::AnalyzeTopLevel || !scopeStmt) { /* Recurse when analyzing include/all OR when not a scope */ stmt->analyzeProgram(ar); } } }
void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) { FunctionCall::analyzeProgram(ar); m_object->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { FunctionScopePtr func = m_funcScope; if (!func && m_object->isThis() && !m_name.empty()) { ClassScopePtr cls = getClassScope(); if (cls) { m_classScope = cls; m_funcScope = func = cls->findFunction(ar, m_name, true, true); if (!func) { cls->addMissingMethod(m_name); } else { func->addCaller(getScope()); } } } markRefParams(func, m_name, canInvokeFewArgs()); } // This is OK because AnalyzeFinal is guaranteed to run for a CPP // target, regardless of opts (and we only need the following // for CPP targets) if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { // necessary because we set the expected type of m_object to // Type::Some during type inference. TypePtr act(m_object->getActualType()); if (!m_object->isThis() && act && act->is(Type::KindOfObject)) { m_object->setExpectedType(act); } } }
void StatementList::analyzeProgramImpl(AnalysisResultPtr ar) { m_included = true; for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr stmt = m_stmts[i]; // effect testing if (ar->isFirstPass() && !stmt->hasEffect() && !stmt->is(Statement::KindOfStatementList)) { ar->getCodeError()->record(shared_from_this(), CodeError::StatementHasNoEffect, stmt); } // changing AUTOLOAD to includes if (ar->getPhase() == AnalysisResult::AnalyzeInclude && stmt->is(Statement::KindOfExpStatement)) { ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt); if (stmt->isFileLevel()) { expStmt->analyzeAutoload(ar); } expStmt->analyzeShortCircuit(ar); } bool scopeStmt = stmt->is(Statement::KindOfFunctionStatement) || stmt->is(Statement::KindOfClassStatement) || stmt->is(Statement::KindOfInterfaceStatement); if (ar->getPhase() != AnalysisResult::AnalyzeTopLevel || !scopeStmt) { /* Recurse when analyzing include/all OR when not a scope */ stmt->analyzeProgram(ar); } } }
void NewObjectExpression::analyzeProgram(AnalysisResultPtr ar) { FunctionCall::analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll || ar->getPhase() == AnalysisResult::AnalyzeFinal) { FunctionScopePtr func; if (!m_name.empty()) { if (ClassScopePtr cls = resolveClass()) { m_name = m_className; func = cls->findConstructor(ar, true); if (func) func->addNewObjCaller(getScope()); } } if (m_params) { markRefParams(func, "", canInvokeFewArgs()); } if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { TypePtr at(getActualType()); if (at && at->isSpecificObject() && !getExpectedType()) { setExpectedType(at); } } } }
void ClosureExpression::analyzeProgram(AnalysisResultPtr ar) { m_func->analyzeProgram(ar); if (m_vars) { m_values->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { getFunctionScope()->addUse(m_func->getFunctionScope(), BlockScope::UseKindClosure); m_func->getFunctionScope()->setClosureVars(m_vars); // closure function's variable table (not containing function's) VariableTablePtr variables = m_func->getFunctionScope()->getVariables(); VariableTablePtr containing = getFunctionScope()->getVariables(); for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); { Symbol *containingSym = containing->addDeclaredSymbol(name, param); containingSym->setPassClosureVar(); Symbol *sym = variables->addDeclaredSymbol(name, param); sym->setClosureVar(); sym->setDeclaration(ConstructPtr()); if (param->isRef()) { sym->setRefClosureVar(); sym->setUsed(); } else { sym->clearRefClosureVar(); sym->clearUsed(); } } } return; } if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { // closure function's variable table (not containing function's) VariableTablePtr variables = m_func->getFunctionScope()->getVariables(); for (int i = 0; i < m_vars->getCount(); i++) { ParameterExpressionPtr param = dynamic_pointer_cast<ParameterExpression>((*m_vars)[i]); const string &name = param->getName(); // so we can assign values to them, instead of seeing CVarRef Symbol *sym = variables->getSymbol(name); if (sym && sym->isParameter()) { sym->setLvalParam(); } } } } FunctionScopeRawPtr container = getFunctionScope()->getContainingNonClosureFunction(); if (container && container->isStatic()) { m_func->getModifiers()->add(T_STATIC); } }
void Construct::addUserClass(AnalysisResultPtr ar, const std::string &name) { if (!name.empty()) { if (ar->getPhase() == AnalysisResult::AnalyzeAll || ar->getPhase() == AnalysisResult::AnalyzeFinal) { getFileScope()->addClassDependency(ar, name); } } }
ExpressionPtr BinaryOpExpression::simplifyLogical(AnalysisResultPtr ar) { if (m_exp1->is(Expression::KindOfConstantExpression)) { ConstantExpressionPtr con = dynamic_pointer_cast<ConstantExpression>(m_exp1); if (con->isBoolean()) { if (con->getBooleanValue()) { if (ar->getPhase() >= AnalysisResult::PostOptimize) { // true && v (true AND v) => v ASSERT(m_exp2->getType()->is(Type::KindOfBoolean)); if (m_op == T_BOOLEAN_AND || m_op == T_LOGICAL_AND) return m_exp2; } // true || v (true OR v) => true if (m_op == T_BOOLEAN_OR || m_op == T_LOGICAL_OR) { return CONSTANT("true"); } } else { if (ar->getPhase() >= AnalysisResult::PostOptimize) { ASSERT(m_exp2->getType()->is(Type::KindOfBoolean)); // false || v (false OR v) => v if (m_op == T_BOOLEAN_OR || m_op == T_LOGICAL_OR) return m_exp2; } // false && v (false AND v) => false if (m_op == T_BOOLEAN_AND || m_op == T_LOGICAL_AND) { return CONSTANT("false"); } } } } if (m_exp2->is(Expression::KindOfConstantExpression)) { ConstantExpressionPtr con = dynamic_pointer_cast<ConstantExpression>(m_exp2); if (con->isBoolean()) { if (con->getBooleanValue()) { if (ar->getPhase() >= AnalysisResult::PostOptimize) { ASSERT(m_exp1->getType()->is(Type::KindOfBoolean)); // v && true (v AND true) => v if (m_op == T_BOOLEAN_AND || m_op == T_LOGICAL_AND) return m_exp1; } // v || true (v OR true) => true when v does not have effect if (m_op == T_BOOLEAN_OR || m_op == T_LOGICAL_OR) { if (!m_exp1->hasEffect()) return CONSTANT("true"); } } else { if (ar->getPhase() >= AnalysisResult::PostOptimize) { ASSERT(m_exp1->getType()->is(Type::KindOfBoolean)); // v || false (v OR false) => v if (m_op == T_BOOLEAN_OR || m_op == T_LOGICAL_OR) return m_exp1; } // v && false (v AND false) => false when v does not have effect if (m_op == T_BOOLEAN_AND || m_op == T_LOGICAL_AND) { if (!m_exp1->hasEffect()) return CONSTANT("false"); } } } } return ExpressionPtr(); }
void Construct::addUserFunction(AnalysisResultPtr ar, const std::string &name) { if (!name.empty()) { if (ar->getPhase() == AnalysisResult::AnalyzeAll || ar->getPhase() == AnalysisResult::AnalyzeFinal) { FunctionScopePtr func = getFunctionScope(); getFileScope()->addFunctionDependency(ar, name, func && func->isInlined()); } } }
void UnaryOpExpression::analyzeProgram(AnalysisResultPtr ar) { if (ar->getPhase() == AnalysisResult::AnalyzeFinal && m_op == '@') { StatementPtr stmt = ar->getStatementForSilencer(); ASSERT(stmt); m_silencer = stmt->requireSilencers(1); } if (m_exp) m_exp->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeFinal && m_op == '@') { StatementPtr stmt = ar->getStatementForSilencer(); ASSERT(stmt); stmt->endRequireSilencers(m_silencer); } }
void SimpleVariable::analyzeProgram(AnalysisResultPtr ar) { m_superGlobal = BuiltinSymbols::IsSuperGlobal(m_name); m_superGlobalType = BuiltinSymbols::GetSuperGlobalType(m_name); VariableTablePtr variables = getScope()->getVariables(); if (m_superGlobal) { variables->setAttribute(VariableTable::NeedGlobalPointer); } else if (m_name == "GLOBALS") { m_globals = true; } else { m_sym = variables->addSymbol(m_name); } if (ar->getPhase() == AnalysisResult::AnalyzeAll) { if (FunctionScopePtr func = getFunctionScope()) { if (m_name == "this" && getClassScope()) { func->setContainsThis(); m_this = true; if (!hasContext(ObjectContext)) { func->setContainsBareThis(); if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ClassScopePtr cls = getClassScope(); TypePtr t = cls->isRedeclaring() ? Type::Variant : Type::CreateObjectType(cls->getName()); variables->add(m_sym, t, true, ar, shared_from_this(), getScope()->getModifiers()); } } } if (m_sym && !(m_context & AssignmentLHS) && !((m_context & UnsetContext) && (m_context & LValue))) { m_sym->setUsed(); } } } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_sym && !m_sym->isSystem() && !(getContext() & (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) && m_sym->getDeclaration().get() == this && !variables->getAttribute(VariableTable::ContainsLDynamicVariable) && !getScope()->is(BlockScope::ClassScope)) { if (getScope()->inPseudoMain()) { Compiler::Error(Compiler::UseUndeclaredGlobalVariable, shared_from_this()); } else { Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this()); } } } }
void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) { FunctionCall::analyzeProgram(ar); m_object->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { FunctionScopePtr func = m_funcScope; if (!func && m_object->isThis() && !m_name.empty()) { ClassScopePtr cls = getClassScope(); if (cls) { m_classScope = cls; func = cls->findFunction(ar, m_name, true, true); if (func && !cls->isInterface() && !(func->isVirtual() && (func->isAbstract() || (func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) && !func->isPerfectVirtual())) { m_funcScope = func; func->addCaller(getScope()); } } } markRefParams(func, m_name, canInvokeFewArgs()); } // This is OK because AnalyzeFinal is guaranteed to run for a CPP // target, regardless of opts (and we only need the following // for CPP targets) if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { // necessary because we set the expected type of m_object to // Type::Some during type inference. TypePtr at(m_object->getActualType()); TypePtr it(m_object->getImplementedType()); if (!m_object->isThis() && at && at->is(Type::KindOfObject)) { if (at->isSpecificObject() && it && Type::IsMappedToVariant(it)) { // fast-cast inference ClassScopePtr scope(ar->findClass(at->getName())); if (scope) { // add a dependency to m_object's class type // to allow the fast cast to succeed addUserClass(ar, at->getName()); } } m_object->setExpectedType(at); } } }
void StaticStatement::analyzeProgramImpl(AnalysisResultPtr ar) { m_exp->analyzeProgram(ar); BlockScopePtr scope = ar->getScope(); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; ExpressionPtr variable; ExpressionPtr value; if (ar->getPhase() == AnalysisResult::AnalyzeInclude) { // turn static $a; into static $a = null; if (exp->is(Expression::KindOfSimpleVariable)) { variable = dynamic_pointer_cast<SimpleVariable>(exp); exp = AssignmentExpressionPtr (new AssignmentExpression(exp->getLocation(), Expression::KindOfAssignmentExpression, variable, CONSTANT("null"), false)); (*m_exp)[i] = exp; } } if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); variable = assignment_exp->getVariable(); value = assignment_exp->getValue(); } else { ASSERT(false); } SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); if (ar->getPhase() == AnalysisResult::AnalyzeInclude) { if (scope->getVariables()->setStaticInitVal(var->getName(), value)) { ar->getCodeError()->record(CodeError::DeclaredStaticVariableTwice, exp); } } else if (ar->getPhase() == AnalysisResult::AnalyzeAll) { // update initial value const string &name = var->getName(); ExpressionPtr initValue = (dynamic_pointer_cast<Expression> (scope->getVariables()->getStaticInitVal(name)))->clone(); exp = AssignmentExpressionPtr (new AssignmentExpression(exp->getLocation(), Expression::KindOfAssignmentExpression, variable, initValue, false)); (*m_exp)[i] = exp; } } }
ExpressionPtr UnaryOpExpression::preOptimize(AnalysisResultPtr ar) { Variant value; Variant result; if (m_exp && ar->getPhase() >= AnalysisResult::FirstPreOptimize) { if (m_op == '(') { return m_exp; } if (m_op == T_UNSET) { if (m_exp->isScalar() || (m_exp->is(KindOfExpressionList) && static_pointer_cast<ExpressionList>(m_exp)->getCount() == 0)) { return CONSTANT("null"); } return ExpressionPtr(); } } if (m_op != T_ARRAY && m_exp && m_exp->isScalar() && m_exp->getScalarValue(value) && preCompute(value, result)) { return replaceValue(makeScalarExpression(ar, result)); } return ExpressionPtr(); }
void ClassStatement::analyzeProgram(AnalysisResultPtr ar) { std::vector<std::string> bases; auto const hasParent = !m_originalParent.empty(); if (hasParent) bases.push_back(m_originalParent); if (m_base) m_base->getStrings(bases); checkVolatile(ar); if (m_stmt) { m_stmt->analyzeProgram(ar); } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { auto const expectClass = hasParent && i == 0; if (expectClass == cls->isInterface() || cls->isTrait()) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), "You are extending " + cls->getOriginalName() + " which is an interface or a trait"); } if (cls->isUserClass()) { cls->addUse(getScope(), BlockScope::UseKindParentRef); } } } }
void IncludeExpression::analyzeInclude(AnalysisResultPtr ar, const std::string &include) { ASSERT(ar->getPhase() == AnalysisResult::AnalyzeInclude); ConstructPtr self = shared_from_this(); FileScopePtr file = ar->findFileScope(include, true); if (!file) { ar->getCodeError()->record(self, CodeError::PHPIncludeFileNotFound, self); return; } if (include.find("compiler/") != 0 || include.find("/compiler/") == string::npos) { ar->getCodeError()->record(self, CodeError::PHPIncludeFileNotInLib, self, ConstructPtr(), include.c_str()); } if (!isFileLevel()) { // Not unsupported but potentially bad ar->getCodeError()->record(self, CodeError::UseDynamicInclude, self); } ar->getDependencyGraph()->add (DependencyGraph::KindOfProgramMaxInclude, ar->getName(), file->getName(), StatementPtr()); ar->getDependencyGraph()->addParent (DependencyGraph::KindOfProgramMinInclude, ar->getName(), file->getName(), StatementPtr()); FunctionScopePtr func = ar->getFunctionScope(); ar->getFileScope()->addIncludeDependency(ar, m_include, func && func->isInlined()); }
void ClassVariable::analyzeProgram(AnalysisResultPtr ar) { m_declaration->analyzeProgram(ar); AnalysisResult::Phase phase = ar->getPhase(); if (phase != AnalysisResult::AnalyzeAll) { return; } if (m_modifiers->isAbstract()) { Compiler::Error(Compiler::AbstractProperty, shared_from_this()); } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; bool error; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); scope->getVariables()->setClassInitVal(var->getName(), value); error = scope->getVariables()->markOverride(ar, var->getName()); } else { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); error = scope->getVariables()->markOverride(ar, var->getName()); scope->getVariables()->setClassInitVal(var->getName(), makeConstant(ar, "null")); } if (error) { Compiler::Error(Compiler::InvalidOverride, exp); } } }
void ClassStatement::analyzeProgramImpl(AnalysisResultPtr ar) { vector<string> bases; if (!m_parent.empty()) bases.push_back(m_parent); if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { string className = bases[i]; addUserClass(ar, bases[i]); } checkVolatile(ar); if (m_stmt) { m_stmt->analyzeProgram(ar); } if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if ((!cls->isInterface() && (m_parent.empty() || i > 0 )) || (cls->isInterface() && (!m_parent.empty() && i == 0 ))) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName()); } if (cls->isUserClass()) { cls->addUse(getScope(), BlockScope::UseKindParentRef); } } } }
void MethodStatement::inferTypes(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar->getPhase() == AnalysisResult::FirstInference && m_stmt) { if (m_stmt->hasRetExp() || funcScope->inPseudoMain() || funcScope->getReturnType()) { bool lastIsReturn = false; if (m_stmt->getCount()) { StatementPtr lastStmt = (*m_stmt)[m_stmt->getCount()-1]; if (lastStmt->is(Statement::KindOfReturnStatement)) { lastIsReturn = true; } } if (!lastIsReturn && !(funcScope->inPseudoMain() && !Option::GenerateCPPMain)) { ExpressionPtr constant = funcScope->inPseudoMain() ? CONSTANT("true") : CONSTANT("null"); ReturnStatementPtr returnStmt = ReturnStatementPtr(new ReturnStatement(getLocation(), Statement::KindOfReturnStatement, constant)); m_stmt->addElement(returnStmt); } } } ar->pushScope(funcScope); if (m_params) { m_params->inferAndCheck(ar, NEW_TYPE(Any), false); } if (m_stmt) { m_stmt->inferTypes(ar); } ar->popScope(); }
void ClassVariable::analyzeProgramImpl(AnalysisResultPtr ar) { m_declaration->analyzeProgram(ar); AnalysisResult::Phase phase = ar->getPhase(); if (phase != AnalysisResult::AnalyzeAll) { return; } ClassScopePtr scope = getClassScope(); for (int i = 0; i < m_declaration->getCount(); i++) { ExpressionPtr exp = (*m_declaration)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment = dynamic_pointer_cast<AssignmentExpression>(exp); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(assignment->getVariable()); ExpressionPtr value = assignment->getValue(); scope->getVariables()->setClassInitVal(var->getName(), value); scope->getVariables()->markOverride(ar, var->getName()); } else { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); scope->getVariables()->markOverride(ar, var->getName()); scope->getVariables()->setClassInitVal(var->getName(), makeConstant(ar, "null")); } } }
StatementPtr StatementList::preOptimize(AnalysisResultPtr ar) { bool del = false; bool changed = false; for (unsigned int i = 0; i < m_stmts.size(); i++) { StatementPtr &s = m_stmts[i]; if (del) { switch (s->getKindOf()) { case Statement::KindOfBlockStatement: case Statement::KindOfIfBranchStatement: case Statement::KindOfIfStatement: case Statement::KindOfWhileStatement: case Statement::KindOfDoStatement: case Statement::KindOfForStatement: case Statement::KindOfSwitchStatement: case Statement::KindOfCaseStatement: case Statement::KindOfBreakStatement: case Statement::KindOfContinueStatement: case Statement::KindOfReturnStatement: case Statement::KindOfGlobalStatement: case Statement::KindOfStaticStatement: case Statement::KindOfEchoStatement: case Statement::KindOfUnsetStatement: case Statement::KindOfExpStatement: case Statement::KindOfForEachStatement: case Statement::KindOfCatchStatement: case Statement::KindOfTryStatement: case Statement::KindOfThrowStatement: removeElement(i--); changed = true; continue; default: break; } } if (s) { ar->preOptimize(s); if (ar->getPhase() != AnalysisResult::AnalyzeInclude && Option::EliminateDeadCode) { if (s->is(KindOfBreakStatement) || s->is(KindOfContinueStatement) || s->is(KindOfReturnStatement) || s->is(KindOfThrowStatement)) { del = true; } else if (s->is(KindOfExpStatement)) { ExpressionPtr e = dynamic_pointer_cast<ExpStatement>(s)->getExpression(); if (!e->hasEffect()) { removeElement(i--); changed = true; } } } } } if (mergeConcatAssign(ar)) changed = true; return changed ? static_pointer_cast<Statement>(shared_from_this()) : StatementPtr(); }
void ArrayElementExpression::analyzeProgram(AnalysisResultPtr ar) { m_variable->analyzeProgram(ar); if (m_offset) m_offset->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (!m_global && (m_context & AccessContext) && !(m_context & (LValue|RefValue|DeepReference| UnsetContext|RefParameter|InvokeArgument))) { TypePtr type = m_variable->getActualType(); if (!type || (!type->is(Type::KindOfString) && !type->is(Type::KindOfArray))) { FunctionScopePtr scope = getFunctionScope(); if (scope) scope->setNeedsRefTemp(); } } if (m_global) { if (getContext() & (LValue|RefValue|DeepReference)) { setContext(NoLValueWrapper); } else if (!m_dynamicGlobal && !(getContext() & (LValue|RefValue|RefParameter|DeepReference| UnsetContext|ExistContext))) { VariableTablePtr vars = ar->getVariables(); Symbol *sym = vars->getSymbol(m_globalName); if (!sym || sym->getDeclaration().get() == this) { Compiler::Error(Compiler::UseUndeclaredVariable, shared_from_this()); } } } } }
void FunctionCall::analyzeProgram(AnalysisResultPtr ar) { if (m_class) m_class->analyzeProgram(ar); if (m_nameExp) m_nameExp->analyzeProgram(ar); if (m_params) m_params->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeFinal) { if (m_funcScope && !m_arrayParams) { for (int i = 0, n = m_funcScope->getMaxParamCount(); i < n; ++i) { if (TypePtr specType = m_funcScope->getParamTypeSpec(i)) { const char *fmt = 0; string ptype; if (!m_params || m_params->getCount() <= i) { if (i >= m_funcScope->getMinParamCount()) break; fmt = "parameter %d of %s() requires %s, none given"; } else { ExpressionPtr param = (*m_params)[i]; if (!Type::Inferred(ar, param->getType(), specType)) { fmt = "parameter %d of %s() requires %s, called with %s"; } ptype = param->getType()->toString(); } if (fmt) { string msg; Util::string_printf (msg, fmt, i + 1, Util::escapeStringForCPP(m_funcScope->getOriginalName()).c_str(), specType->toString().c_str(), ptype.c_str()); Compiler::Error(Compiler::BadArgumentType, shared_from_this(), msg); } } } } } }
StatementPtr ExpStatement::preOptimize(AnalysisResultPtr ar) { if (ar->getPhase() != AnalysisResult::AnalyzeInclude) { m_exp = m_exp->unneeded(ar); } ar->preOptimize(m_exp); return StatementPtr(); }
void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) { FunctionScopePtr funcScope = m_funcScope.lock(); if (ar->isAnalyzeInclude()) { if (funcScope->isSepExtension() || BuiltinSymbols::IsDeclaredDynamic(m_name) || Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) { funcScope->setDynamic(); } } funcScope->setIncludeLevel(ar->getIncludeLevel()); if (m_params) { m_params->analyzeProgram(ar); if (Option::GenRTTIProfileData && ar->getPhase() == AnalysisResult::AnalyzeFinal) { addParamRTTI(ar); } } if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->isAnalyzeInclude()) { if (!funcScope->isStatic() && getClassScope() && funcScope->getVariables()-> getAttribute(VariableTable::ContainsDynamicVariable)) { // Add this to variable table if we'll need it in a lookup table // Use object because there's no point to specializing, just makes // code gen harder when dealing with redeclared classes. TypePtr tp(Type::Object); funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(), ModifierExpressionPtr()); } FunctionScope::RecordRefParamInfo(m_name, funcScope); } }
void UnaryOpExpression::analyzeProgram(AnalysisResultPtr ar) { if (m_exp) m_exp->analyzeProgram(ar); if ((m_op == T_CLASS || m_op == T_FUNCTION) && ar->getPhase() == AnalysisResult::AnalyzeFinal) { ar->link(getFileScope(), m_definedScope->getContainingFile()); } }
void InterfaceStatement::analyzeProgramImpl(AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (m_stmt) { classScope->setIncludeLevel(ar->getIncludeLevel()); m_stmt->analyzeProgram(ar); } ar->recordClassSource(m_name, m_loc, getFileScope()->getName()); checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector<string> bases; if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { addUserClass(ar, bases[i]); ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { Compiler::Error(Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName()); } if (cls->isUserClass()) { cls->addUse(classScope, BlockScope::UseKindParentRef); } } } }
void SwitchStatement::analyzeProgram(AnalysisResultPtr ar) { m_exp->analyzeProgram(ar); if (m_cases) m_cases->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll && m_exp->is(Expression::KindOfSimpleVariable)) { auto exp = dynamic_pointer_cast<SimpleVariable>(m_exp); if (exp && exp->getSymbol() && exp->getSymbol()->isClassName()) { // Mark some classes as volatile since the name is used in switch for (int i = 0; i < m_cases->getCount(); i++) { auto stmt = dynamic_pointer_cast<CaseStatement>((*m_cases)[i]); assert(stmt); ExpressionPtr caseCond = stmt->getCondition(); if (caseCond && caseCond->isScalar()) { auto name = dynamic_pointer_cast<ScalarExpression>(caseCond); if (name && name->isLiteralString()) { string className = name->getLiteralString(); ClassScopePtr cls = ar->findClass(toLower(className)); if (cls && cls->isUserClass()) { cls->setVolatile(); } } } } // Also note this down as code error ConstructPtr self = shared_from_this(); Compiler::Error(Compiler::ConditionalClassLoading, self); } } }
void ObjectMethodExpression::analyzeProgram(AnalysisResultPtr ar) { Expression::analyzeProgram(ar); m_params->analyzeProgram(ar); m_object->analyzeProgram(ar); m_nameExp->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { FunctionScopePtr func = m_funcScope; if (!func && m_object->isThis() && !m_name.empty()) { ClassScopePtr cls = getClassScope(); if (cls) { m_classScope = cls; m_funcScope = func = cls->findFunction(ar, m_name, true, true); if (!func) { cls->addMissingMethod(m_name); } else { func->addCaller(getScope()); } } } markRefParams(func, m_name, canInvokeFewArgs()); } }
void InterfaceStatement::analyzeProgram(AnalysisResultPtr ar) { ClassScopeRawPtr classScope = getClassScope(); if (m_stmt) { m_stmt->analyzeProgram(ar); } checkVolatile(ar); if (ar->getPhase() != AnalysisResult::AnalyzeAll) return; vector<string> bases; if (m_base) m_base->getStrings(bases); for (unsigned int i = 0; i < bases.size(); i++) { ClassScopePtr cls = ar->findClass(bases[i]); if (cls) { if (!cls->isInterface()) { Compiler::Error( Compiler::InvalidDerivation, shared_from_this(), cls->getOriginalName() + " must be an interface"); } if (cls->isUserClass()) { cls->addUse(classScope, BlockScope::UseKindParentRef); } } } }
void FinallyStatement::analyzeProgram(AnalysisResultPtr ar) { if (m_stmt) m_stmt->analyzeProgram(ar); if (ar->getPhase() == AnalysisResult::AnalyzeAll) { FunctionScopeRawPtr fs = getFunctionScope(); if (fs) fs->setHasTry(); } }