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);
    }
  }
}
Exemple #4
0
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);
  }

}
Exemple #6
0
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();
}
Exemple #8
0
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);
  }
}
Exemple #10
0
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);
          }
        }
      }
    }
  }
}
Exemple #23
0
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();
  }
}