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; } } }
void GlobalStatement::inferTypes(AnalysisResultPtr ar) { BlockScopePtr scope = ar->getScope(); scope->getVariables()->setAttribute(VariableTable::InsideGlobalStatement); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); VariableTablePtr variables = scope->getVariables(); const std::string &name = var->getName(); /* If we have already seen this variable in the current scope and it is not a global variable, record this variable as "redeclared" which will force Variant type. */ variables->checkRedeclared(name, KindOfGlobalStatement); /* If this is not a top-level global statement, the variable also needs to be Variant type. This should not be a common use case in php code. */ if (!isTopLevel()) { variables->addNestedGlobal(name); } var->setContext(Expression::Declaration); var->inferAndCheck(ar, NEW_TYPE(Any), true); if (variables->needLocalCopy(name)) { variables->forceVariant(ar, name); variables->setAttribute(VariableTable::NeedGlobalPointer); } ConstructPtr decl = ar->getVariables()->getDeclaration(var->getName()); if (decl) { ar->getDependencyGraph()->add(DependencyGraph::KindOfGlobalVariable, ar->getName(), var->getName(), var, var->getName(), decl); } } else { if (ar->isFirstPass()) { ar->getCodeError()->record(shared_from_this(), CodeError::UseDynamicGlobal, exp); } m_dynamicGlobal = true; } } FunctionScopePtr func = ar->getFunctionScope(); scope->getVariables()->clearAttribute(VariableTable::InsideGlobalStatement); }
void AssignmentExpression::onParse(AnalysisResultPtr ar, BlockScopePtr scope) { // This is that much we can do during parse phase. TypePtr type; if (m_value->is(Expression::KindOfScalarExpression)) { type = m_value->inferAndCheck(ar, Type::Some, false); } else if (m_value->is(Expression::KindOfUnaryOpExpression)) { UnaryOpExpressionPtr uexp = dynamic_pointer_cast<UnaryOpExpression>(m_value); if (uexp->getOp() == T_ARRAY) { type = Type::Array; } } if (!type) type = Type::Some; if (m_variable->is(Expression::KindOfConstantExpression)) { // ...as in ClassConstant statement // We are handling this one here, not in ClassConstant, purely because // we need "value" to store in constant table. ConstantExpressionPtr exp = dynamic_pointer_cast<ConstantExpression>(m_variable); scope->getConstants()->add(exp->getName(), type, m_value, ar, m_variable); } else if (m_variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(m_variable); scope->getVariables()->add(var->getName(), type, true, ar, shared_from_this(), scope->getModifiers()); var->clearContext(Declaration); // to avoid wrong CodeError } else { ASSERT(false); // parse phase shouldn't handle anything else } }
void CatchStatement::inferTypes(AnalysisResultPtr ar) { ClassScopePtr cls = ar->findClass(m_className); TypePtr type; m_valid = cls; if (!m_valid) { if (ar->isFirstPass()) { ConstructPtr self = shared_from_this(); ar->getCodeError()->record(self, CodeError::UnknownClass, self); } type = NEW_TYPE(Object); } else if (cls->isRedeclaring()) { type = NEW_TYPE(Object); } else { type = Type::CreateObjectType(m_className); } BlockScopePtr scope = ar->getScope(); VariableTablePtr variables = scope->getVariables(); variables->add(m_variable, type, false, ar, shared_from_this(), ModifierExpressionPtr(), false); if (ar->isFirstPass()) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func && variables->isParameter(m_variable)) { variables->addLvalParam(m_variable); } } if (m_stmt) m_stmt->inferTypes(ar); }
void GlobalStatement::inferTypes(AnalysisResultPtr ar) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); BlockScopePtr scope = getScope(); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; VariableTablePtr variables = scope->getVariables(); variables->setAttribute(VariableTable::NeedGlobalPointer); if (exp->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); const std::string &name = var->getName(); /* If we have already seen this variable in the current scope and it is not a global variable, record this variable as "redeclared" which will force Variant type. */ variables->setAttribute(VariableTable::InsideGlobalStatement); variables->checkRedeclared(name, KindOfGlobalStatement); variables->addLocalGlobal(name); var->setContext(Expression::Declaration); var->inferAndCheck(ar, Type::Any, true); variables->forceVariant(ar, name, VariableTable::AnyVars); variables->clearAttribute(VariableTable::InsideGlobalStatement); } else { variables->forceVariants(ar, VariableTable::AnyVars); variables->setAttribute(VariableTable::ContainsLDynamicVariable); assert(exp->is(Expression::KindOfDynamicVariable)); exp->inferAndCheck(ar, Type::Any, true); } } }
void GlobalStatement::outputCPP(CodeGenerator &cg, AnalysisResultPtr ar) { if (m_dynamicGlobal) { cg.printf("throw_fatal(\"dynamic global\");\n"); } else if (!ar->getScope()->inPseudoMain() || !isTopLevel()) { BlockScopePtr scope = ar->getScope(); if (m_exp->getCount() > 1) cg.indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); const string &name = var->getName(); VariableTablePtr variables = scope->getVariables(); if (variables->needLocalCopy(name)) { cg.printf("%s%s = ref(g->%s);\n", Option::VariablePrefix, name.c_str(), variables->getGlobalVariableName(ar, name).c_str()); } } else { // type inference should have set m_dynamicGlobal to true. ASSERT(false); } } if (m_exp->getCount() > 1) cg.indentEnd("}\n"); } }
void GlobalStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { BlockScopePtr scope = getScope(); if (m_exp->getCount() > 1) cg_indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(exp); const string &name = var->getName(); VariableTablePtr variables = scope->getVariables(); if (variables->needLocalCopy(name)) { cg_printf("%s%s = ref(g->%s);\n", Option::VariablePrefix, name.c_str(), variables->getGlobalVariableName(cg, ar, name).c_str()); } } else if (exp->is(Expression::KindOfDynamicVariable)) { DynamicVariablePtr var = dynamic_pointer_cast<DynamicVariable>(exp); ExpressionPtr exp = var->getSubExpression(); exp->outputCPPBegin(cg, ar); int id = cg.createNewLocalId(shared_from_this()); cg_printf("CStrRef dgv_%d((", id); exp->outputCPP(cg, ar); cg_printf("));\n"); cg_printf("variables->get(dgv_%d) = ref(g->get(dgv_%d));\n", id, id); exp->outputCPPEnd(cg, ar); } else { assert(false); } } if (m_exp->getCount() > 1) cg_indentEnd("}\n"); }
void StaticStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) { BlockScopePtr scope = getScope(); if (scope->inPseudoMain()) { if (m_exp->getCount() > 1) cg_indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { exp->outputCPP(cg, ar); cg_printf(";\n"); } else { ASSERT(false); } } if (m_exp->getCount() > 1) cg_indentEnd("}\n"); return; } VariableTablePtr variables = scope->getVariables(); if (m_exp->getCount() > 1) cg_indentBegin("{\n"); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr variable = assignment_exp->getVariable(); SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); assert(var->hasContext(Expression::Declaration)); const std::string &name = var->getName(); if (variables->needLocalCopy(name)) { ASSERT(var->hasAssignableCPPVariable()); cg_printf("%s.assignRef(%s%s);\n", var->getAssignableCPPVariable(ar).c_str(), Option::StaticVariablePrefix, name.c_str()); } cg_indentBegin("if (!%s%s%s) {\n", Option::InitPrefix, Option::StaticVariablePrefix, name.c_str()); exp->outputCPP(cg, ar); cg_printf(";\n"); cg_printf("%s%s%s = true;\n", Option::InitPrefix, Option::StaticVariablePrefix, name.c_str()); cg_indentEnd("}\n"); } else { ASSERT(false); } } if (m_exp->getCount() > 1) cg_indentEnd("}\n"); }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_sym && m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } if (m_this) { ClassScopePtr cls = getOriginalClass(); if (!hasContext(ObjectContext) && cls->derivedByDynamic()) { ret = Type::Object; } else { ret = Type::CreateObjectType(cls->getName()); } if (!hasContext(ObjectContext) && variables->getAttribute(VariableTable::ContainsDynamicVariable)) { ret = variables->add(m_sym, ret, true, ar, construct, scope->getModifiers()); } } else if ((m_context & (LValue|Declaration)) && !(m_context & (ObjectContext|RefValue))) { if (m_globals) { ret = Type::Variant; } else if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system ret = variables->add(m_sym, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } else { ret = variables->add(m_sym, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { // ClassVariable expression will come to this block of code ret = getClassScope()->checkProperty(m_sym, type, true, ar); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } int p; ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct, p); } } TypePtr actual = propagateTypes(ar, ret); setTypes(ar, actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope()); resetTypes(); TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_sym && m_sym->isParameter() && m_context & (LValue | RefValue | DeepReference | UnsetContext | InvokeArgument | OprLValue | DeepOprLValue)) { m_sym->setLvalParam(); } if (coerce && m_sym && type && type->is(Type::KindOfAutoSequence)) { TypePtr t = m_sym->getType(); if (!t || t->is(Type::KindOfVoid) || t->is(Type::KindOfSome) || t->is(Type::KindOfArray)) { type = Type::Array; } } if (m_this) { ret = Type::Object; ClassScopePtr cls = getOriginalClass(); if (cls && (hasContext(ObjectContext) || !cls->derivedByDynamic())) { ret = Type::CreateObjectType(cls->getName()); } if (!hasContext(ObjectContext) && variables->getAttribute(VariableTable::ContainsDynamicVariable)) { if (variables->getAttribute(VariableTable::ContainsLDynamicVariable)) { ret = Type::Variant; } ret = variables->add(m_sym, ret, true, ar, construct, scope->getModifiers()); } } else if ((m_context & (LValue|Declaration)) && !(m_context & (ObjectContext|RefValue))) { if (m_globals) { ret = Type::Array; } else if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system ret = variables->add(m_sym, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } else { ret = variables->add(m_sym, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { assert(getClassScope().get() == scope.get()); // ClassVariable expression will come to this block of code ret = getClassScope()->checkProperty(getScope(), m_sym, type, true, ar); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } ret = variables->checkVariable(m_sym, tmpType, coerce, ar, construct); if (ret && (ret->is(Type::KindOfSome) || ret->is(Type::KindOfAny))) { ret = Type::Variant; } } } // if m_assertedType is set, then this is a type assertion node TypePtr inType = m_assertedType ? GetAssertedInType(ar, m_assertedType, ret) : ret; TypePtr actual = propagateTypes(ar, inType); setTypes(ar, actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }
void StaticStatement::inferTypes(AnalysisResultPtr ar) { BlockScopePtr scope = ar->getScope(); if (scope->inPseudoMain()) { // static just means to unset at global level for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr variable = assignment_exp->getVariable(); if (variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); var->setContext(Expression::Declaration); scope->getVariables()->forceVariant(ar, var->getName(), VariableTable::AnyStaticVars); } else { ASSERT(false); } } else { // Expression was optimized away; remove it m_exp->removeElement(i--); } } m_exp->inferTypes(ar, Type::Any, true); return; } scope->getVariables()->setAttribute(VariableTable::InsideStaticStatement); for (int i = 0; i < m_exp->getCount(); i++) { ExpressionPtr exp = (*m_exp)[i]; VariableTablePtr variables = scope->getVariables(); if (exp->is(Expression::KindOfAssignmentExpression)) { AssignmentExpressionPtr assignment_exp = dynamic_pointer_cast<AssignmentExpression>(exp); ExpressionPtr variable = assignment_exp->getVariable(); if (variable->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr var = dynamic_pointer_cast<SimpleVariable>(variable); var->setContext(Expression::Declaration); const std::string &name = var->getName(); /* If we have already seen this variable in the current scope and it is not a static variable, record this variable as "redeclared" to force Variant type. */ if (ar->isFirstPass()) { variables->checkRedeclared(name, KindOfStaticStatement); } /* If this is not a top-level static statement, the variable also needs to be Variant type. This should not be a common use case in php code. */ if (!isTopLevel()) { variables->addNestedStatic(name); } if (variables->needLocalCopy(name)) { variables->forceVariant(ar, name, VariableTable::AnyStaticVars); } } else { ASSERT(false); } } else { // Expression was optimized away; remove it m_exp->removeElement(i--); continue; } exp->inferAndCheck(ar, Type::Any, false); } scope->getVariables()->clearAttribute(VariableTable::InsideStaticStatement); }
TypePtr SimpleVariable::inferAndCheck(AnalysisResultPtr ar, TypePtr type, bool coerce) { TypePtr ret; ConstructPtr construct = shared_from_this(); BlockScopePtr scope = ar->getScope(); VariableTablePtr variables = scope->getVariables(); // check function parameter that can occur in lval context if (m_context & (LValue | RefValue | UnsetContext | InvokeArgument)) { FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func) { if (variables->isParameter(m_name)) { variables->addLvalParam(m_name); } } } if (m_name == "this") { ClassScopePtr cls = getOriginalScope(ar); if (cls) { bool isStaticFunc = false; FunctionScopePtr func = dynamic_pointer_cast<FunctionScope>(scope); if (func->isStatic()) isStaticFunc = true; if (cls->isRedeclaring()) { ret = Type::Variant; } else { ret = Type::CreateObjectType(cls->getName()); } if (!isStaticFunc || (m_context & ObjectContext)) m_this = true; } } if ((m_context & (LValue|Declaration)) && !(m_context & ObjectContext)) { if (m_superGlobal) { ret = m_superGlobalType; } else if (m_superGlobalType) { // For system if (!m_this) { ret = variables->add(m_name, m_superGlobalType, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } else { if (m_globals) { ret = Type::Variant; // this can happen with "unset($GLOBALS)" } else if (!m_this) { ret = variables->add(m_name, type, ((m_context & Declaration) != Declaration), ar, construct, scope->getModifiers()); } } } else { if (!m_this) { if (m_superGlobalType) { ret = m_superGlobalType; } else if (m_globals) { ret = Type::Array; } else if (scope->is(BlockScope::ClassScope)) { // ClassVariable expression will come to this block of code int properties; ret = variables->checkProperty(m_name, type, true, ar, construct, properties); } else { TypePtr tmpType = type; if (m_context & RefValue) { tmpType = Type::Variant; coerce = true; } int p; ret = variables->checkVariable(m_name, tmpType, coerce, ar, construct, p); } } } TypePtr actual = propagateTypes(ar, ret); setTypes(actual, type); if (Type::SameType(actual, ret)) { m_implementedType.reset(); } else { m_implementedType = ret; } return actual; }