Exemplo n.º 1
0
void BuiltinSymbols::ImportExtClasses(AnalysisResultPtr ar) {
  const ClassInfo::ClassMap &classes = ClassInfo::GetClassesMap();
  for (auto it = classes.begin(); it != classes.end(); ++it) {
    ClassScopePtr cl = ImportClassScopePtr(ar, it->second);
    assert(!s_classes[cl->getName()]);
    s_classes[cl->getName()] = cl;
  }
}
Exemplo n.º 2
0
TypePtr Type::Union(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
  if (SameType(type1, type2)) {
    return type1;
  }

  int resultKind = type1->m_kindOf | type2->m_kindOf;
  if (resultKind == KindOfObject) {
    std::string resultName("");

    // if they're the same, or we don't know one's name, then use
    // the other
    if (type1->m_name == type2->m_name) {
      resultName = type1->m_name;
    } else if (type1->m_name.empty() || type2->m_name.empty()) {
      // resultName was initialized to "", so leave it as such;
      // we know it's an object but not what kind.
    } else {
      // take the superclass
      ClassScopePtr res =
        ClassScope::FindCommonParent(ar, type1->m_name,
                                         type2->m_name);
      if (res) resultName = res->getName();
    }
    return TypePtr(Type::CreateObjectType(resultName));
  }

  return GetType((KindOf)resultKind);
}
ClassScopePtr ObjectMethodExpression::resolveClass(AnalysisResultPtr ar,
                                                   string &name) {
  ClassScopePtr cls = ar->findClass(name, AnalysisResult::MethodName);
  if (cls) {
    addUserClass(ar, cls->getName());
    return cls;
  }
  string construct("__construct");
  cls = ar->findClass(construct, AnalysisResult::MethodName);
  if (cls && name == cls->getName()) {
    name = "__construct";
    cls->setAttribute(ClassScope::ClassNameConstructor);
    return cls;
  }
  return ClassScopePtr();
}
Exemplo n.º 4
0
bool FileScope::addClass(AnalysisResultConstPtr ar, ClassScopePtr classScope) {
  if (ar->declareClass(classScope)) {
    m_classes[classScope->getName()].push_back(classScope);
    return true;
  }
  return false;
}
Exemplo n.º 5
0
void MethodStatement::onParse(AnalysisResultPtr ar, BlockScopePtr scope) {
  ClassScopePtr classScope = dynamic_pointer_cast<ClassScope>(scope);
  FunctionScopePtr fs = getFunctionScope();

  fs->setParamCounts(ar, -1, -1);
  classScope->addFunction(ar, fs);

  if (m_name == "__construct") {
    classScope->setAttribute(ClassScope::HasConstructor);
  } else if (m_name == "__destruct") {
    classScope->setAttribute(ClassScope::HasDestructor);
  }

  if (m_name == "__call") {
    classScope->setAttribute(ClassScope::HasUnknownMethodHandler);
  } else if (m_name == "__get") {
    classScope->setAttribute(ClassScope::HasUnknownPropGetter);
  } else if (m_name == "__set") {
    classScope->setAttribute(ClassScope::HasUnknownPropSetter);
  } else if (m_name == "__call") {
    classScope->setAttribute(ClassScope::HasUnknownMethodHandler);
  } else if (m_name == "__callstatic") {
    classScope->setAttribute(ClassScope::HasUnknownStaticMethodHandler);
  }

  m_className = classScope->getName();
  m_originalClassName = classScope->getOriginalName();
}
Exemplo n.º 6
0
TypePtr NewObjectExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
                                        bool coerce) {
  reset();
  ConstructPtr self = shared_from_this();
  if (!m_name.empty()) {
    ClassScopePtr cls = ar->resolveClass(m_name);
    if (cls) {
      m_name = cls->getName();
    }
    if (!cls || cls->isRedeclaring()) {
      if (cls) {
        m_redeclared = true;
        ar->getScope()->getVariables()->
          setAttribute(VariableTable::NeedGlobalPointer);
      }
      if (!cls && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::UnknownClass, self);
      }
      if (m_params) m_params->inferAndCheck(ar, NEW_TYPE(Any), false);
      return NEW_TYPE(Object);
    }
    if (cls->isVolatile()) {
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
    }
    m_dynamic = cls->derivesFromRedeclaring();
    m_validClass = true;
    FunctionScopePtr func = cls->findConstructor(ar, true);
    if (!func) {
      if (m_params) {
        if (!m_dynamic && m_params->getCount()) {
          if (ar->isFirstPass()) {
            ar->getCodeError()->record(self, CodeError::BadConstructorCall,
                                       self);
          }
          m_params->setOutputCount(0);
        }
        m_params->inferAndCheck(ar, NEW_TYPE(Any), false);
      }
    } else {
      m_extraArg = func->inferParamTypes(ar, self, m_params,
                                         m_validClass);
      m_variableArgument = func->isVariableArgument();
    }
    return Type::CreateObjectType(m_name);
  } else {
    ar->containsDynamicClass();
    if (ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UseDynamicClass,
                                 self);
    }
    if (m_params) {
      m_params->markParams(false);
    }
  }

  m_nameExp->inferAndCheck(ar, Type::String, false);
  if (m_params) m_params->inferAndCheck(ar, NEW_TYPE(Any), false);
  return Type::Variant;//NEW_TYPE(Object);
}
Exemplo n.º 7
0
bool AnalysisResult::checkClassPresent(ConstructPtr cs,
                                       const std::string &name) const {
  if (name == "self" || name == "parent") return true;
  std::string lowerName = toLower(name);
  if (ClassScopePtr currentCls = cs->getClassScope()) {
    if (lowerName == currentCls->getName() ||
        currentCls->derivesFrom(shared_from_this(), lowerName,
                                true, false)) {
      return true;
    }
  }
  if (FileScopePtr currentFile = cs->getFileScope()) {
    StatementList &stmts = *currentFile->getStmt();
    for (int i = stmts.getCount(); i--; ) {
      StatementPtr s = stmts[i];
      if (s && s->is(Statement::KindOfClassStatement)) {
        ClassScopePtr scope =
          static_pointer_cast<ClassStatement>(s)->getClassScope();
        if (lowerName == scope->getName()) {
          return true;
        }
        if (scope->derivesFrom(shared_from_this(), lowerName,
                               true, false)) {
          return true;
        }
      }
    }
  }
  return false;
}
Exemplo n.º 8
0
void ParameterExpression::fixupSelfAndParentTypehints(ClassScopePtr cls) {
  if (m_type == "self") {
    m_type = cls->getName();
  } else if (m_type == "parent") {
    if (!cls->getOriginalParent().empty()) {
      m_type = toLower(cls->getOriginalParent());
    }
  }
}
Exemplo n.º 9
0
ClassScopePtr AnalysisResult::findExactClass(ConstructPtr cs,
                                             const std::string &name) const {
  ClassScopePtr cls = findClass(name);
  if (!cls || !cls->isRedeclaring()) return cls;
  if (ClassScopePtr currentCls = cs->getClassScope()) {
    if (cls->getName() == currentCls->getName()) {
      return currentCls;
    }
  }
  return ClassScopePtr();
}
Exemplo n.º 10
0
void FunctionScope::outputCPPCreateImpl(CodeGenerator &cg,
                                        AnalysisResultPtr ar) {
  ClassScopePtr scope = ar->getClassScope();
  string clsNameStr = scope->getId(cg);
  const char *clsName = clsNameStr.c_str();
  const char *consName = scope->classNameCtor() ? scope->getName().c_str()
                                                : "__construct";

  cg_printf("%s%s *%s%s::create(",
            Option::ClassPrefix, clsName, Option::ClassPrefix, clsName);
  outputCPPParamsImpl(cg, ar);
  cg_indentBegin(") {\n");
  cg_printf("CountableHelper h(this);\n");
  cg_printf("init();\n");
  cg_printf("%s%s(", Option::MethodPrefix, consName);
  outputCPPParamsCall(cg, ar, false);
  cg_printf(");\n");
  cg_printf("return this;\n");
  cg_indentEnd("}\n");
  cg_indentBegin("ObjectData *%s%s::dynCreate(CArrRef params, "
                 "bool construct /* = true */) {\n",
                 Option::ClassPrefix, clsName);
  cg_printf("init();\n");
  cg_indentBegin("if (construct) {\n");
  cg_printf("CountableHelper h(this);\n");
  OutputCPPDynamicInvokeCount(cg);
  outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix,
                         cg.formatLabel(consName).c_str(),
                         true, false, false, NULL, true);
  cg_indentEnd("}\n");
  cg_printf("return this;\n");
  cg_indentEnd("}\n");
  if (isDynamic() || isSepExtension()) {
    cg_indentBegin("void %s%s::dynConstruct(CArrRef params) {\n",
                   Option::ClassPrefix, clsName);
    OutputCPPDynamicInvokeCount(cg);
    outputCPPDynamicInvoke(cg, ar, Option::MethodPrefix,
                           cg.formatLabel(consName).c_str(),
                           true, false, false, NULL, true);
    cg_indentEnd("}\n");
    if (cg.getOutput() == CodeGenerator::SystemCPP ||
        Option::EnableEval >= Option::LimitedEval) {
      cg_indentBegin("void %s%s::dynConstructFromEval("
                     "Eval::VariableEnvironment &env, "
                     "const Eval::FunctionCallExpression *caller) {\n",
                     Option::ClassPrefix, clsName);
      outputCPPEvalInvoke(cg, ar, Option::MethodPrefix,
                          cg.formatLabel(consName).c_str(), NULL, false);
      cg_indentEnd("}\n");
    }
  }
}
Exemplo n.º 11
0
void ParameterExpression::parseHandler(AnalysisResultConstPtr ar,
                                       FunctionScopePtr func,
                                       ClassScopePtr cls) {
  if (cls && !m_type.empty()) {
    if (m_type == "self") {
      m_type = cls->getName();
    } else if (m_type == "parent") {
      if (!cls->getParent().empty()) {
        m_type = cls->getParent();
      }
    }
  }
  func->getVariables()->addParam(m_name, TypePtr(), ar, ExpressionPtr());
}
Exemplo n.º 12
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 ClassConstantExpression::outputCPPImpl(CodeGenerator &cg,
                                            AnalysisResultPtr ar) {
  const char *globals = "g";
  if (cg.getContext() == CodeGenerator::CppParameterDefaultValueDecl ||
      cg.getContext() == CodeGenerator::CppParameterDefaultValueImpl) {
    globals = cg.getGlobals();
  }
  if (m_valid) {
    ClassScopePtr foundCls;
    string trueClassName;
    for (ClassScopePtr cls = ar->findClass(m_className);
         cls; cls = cls->getParentScope(ar)) {
      if (cls->getConstants()->isPresent(m_varName)) {
        foundCls = cls;
        trueClassName = cls->getName();
        break;
      }
    }
    ASSERT(!trueClassName.empty());
    ConstructPtr decl = foundCls->getConstants()->getValue(m_varName);
    if (decl) {
      decl->outputCPP(cg, ar);
      if (cg.getContext() == CodeGenerator::CppImplementation ||
          cg.getContext() == CodeGenerator::CppParameterDefaultValueImpl) {
        cg.printf("(%s::%s)", m_className.c_str(), m_varName.c_str());
      } else {
        cg.printf("/* %s::%s */", m_className.c_str(), m_varName.c_str());
      }
    } else {
      if (foundCls->getConstants()->isDynamic(m_varName)) {
        cg.printf("%s%s::lazy_initializer(%s)->", Option::ClassPrefix,
                  trueClassName.c_str(), globals);
      }
      cg.printf("%s%s_%s", Option::ClassConstantPrefix, trueClassName.c_str(),
                m_varName.c_str());
    }
  } else if (m_redeclared) {
    cg.printf("%s->%s%s->os_constant(\"%s\")", globals,
              Option::ClassStaticsObjectPrefix,
              m_className.c_str(), m_varName.c_str());
  } else {
    cg.printf("throw_fatal(\"unknown class constant %s::%s\")",
              m_className.c_str(), m_varName.c_str());
  }
}
Exemplo n.º 14
0
void MethodStatement::onParse(AnalysisResultPtr ar) {
  ClassScopePtr classScope =
    dynamic_pointer_cast<ClassScope>(ar->getScope());

  classScope->addFunction(ar, onParseImpl(ar));
  if (m_name == "__construct") {
    classScope->setAttribute(ClassScope::HasConstructor);
  } else if (m_name == "__destruct") {
    classScope->setAttribute(ClassScope::HasDestructor);
  }

  if (m_name == "__call") {
    classScope->setAttribute(ClassScope::HasUnknownMethodHandler);
  } else if (m_name == "__get") {
    classScope->setAttribute(ClassScope::HasUnknownPropHandler);
  }

  m_className = classScope->getName();
}
Exemplo n.º 15
0
ClassScopePtr BlockScope::findExactClass(const std::string &className) {
  if (ClassScopePtr currentCls = getContainingClass()) {
    if (className == currentCls->getName()) {
      return currentCls;
    }
  }
  if (FileScopePtr currentFile = getContainingFile()) {
    StatementList &stmts = *currentFile->getStmt();
    for (int i = stmts.getCount(); i--; ) {
      StatementPtr s = stmts[i];
      if (s && s->is(Statement::KindOfClassStatement)) {
        ClassScopePtr scope =
          static_pointer_cast<ClassStatement>(s)->getClassScope();
        if (className == scope->getName()) {
          return scope;
        }
      }
    }
  }
  return ClassScopePtr();
}
Exemplo n.º 16
0
bool AnalysisResult::declareClass(ClassScopePtr classScope) const {
  assert(m_phase < AnalyzeAll);

  string cname = classScope->getName();
  // System classes override
  if (m_systemClasses.find(cname) != m_systemClasses.end()) {
    // we need someone to hold on to a reference to it
    // even though we're not going to do anything with it
    this->lock()->m_ignoredScopes.push_back(classScope);
    return false;
  }

  int mask =
    (m_classForcedVariants[0] ? VariableTable::NonPrivateNonStaticVars : 0) |
    (m_classForcedVariants[1] ? VariableTable::NonPrivateStaticVars : 0);

  if (mask) {
    AnalysisResultConstPtr ar = shared_from_this();
    classScope->getVariables()->forceVariants(ar, mask);
  }
  return true;
}
Exemplo n.º 17
0
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;
}
Exemplo n.º 18
0
void InterfaceStatement::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
  ClassScopeRawPtr classScope = getClassScope();
  if (cg.getContext() == CodeGenerator::NoContext) {
    if (classScope->isVolatile()) {
      const vector<string> &bases = classScope->getBases();
      for (unsigned i = 0; i < bases.size(); ++i) {
        const string &name = bases[i];
        if (cg.checkHoistedClass(name) ||
            classScope->hasKnownBase(i)) {
          continue;
        }
        ClassScopePtr base = ar->findClass(name);
        if (base && base->isVolatile()) {
          cg_printf("checkClassExistsThrow(");
          cg_printString(name, ar, shared_from_this());
          cg_printf(", &%s->CDEC(%s));\n",
                    cg.getGlobals(ar),
                    CodeGenerator::FormatLabel(base->getName()).c_str());
        }
      }
      classScope->outputCPPDef(cg);
      cg.addHoistedClass(m_name);
    }
    return;
  }

  string clsNameStr = classScope->getId();
  const char *clsName = clsNameStr.c_str();

  switch (cg.getContext()) {
  case CodeGenerator::CppDeclaration:
    {
      printSource(cg);
      if (Option::GenerateCPPMacros) {
        classScope->outputForwardDeclaration(cg);
      }
      if (classScope->isRedeclaring()) {
        classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
      }
      cg_printf("class %s%s", Option::ClassPrefix, clsName);
      if (m_base && Option::UseVirtualDispatch &&
          !classScope->isRedeclaring()) {
        const char *sep = " :";
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && !intfClassScope->isRedeclaring() &&
              classScope->derivesDirectlyFrom(intf)) {
            string id = intfClassScope->getId();
            cg_printf("%s public %s%s", sep, Option::ClassPrefix, id.c_str());
            sep = ",";
          }
        }
      }
      cg_indentBegin(" {\n");
      if (m_stmt) m_stmt->outputCPP(cg, ar);

      bool hasPropTable = classScope->checkHasPropTable(ar);
      if (hasPropTable) {
        cg_printf("public: static const ClassPropTable %sprop_table;\n",
                  Option::ObjectStaticPrefix);
      }

      cg_indentEnd("};\n");
      if (hasPropTable) {
        classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
      }
      if (m_stmt) {
        cg.setContext(CodeGenerator::CppClassConstantsDecl);
        m_stmt->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::CppDeclaration);
      }
    }
    break;
  case CodeGenerator::CppImplementation:
    {
      if (m_stmt) {
        cg.setContext(CodeGenerator::CppClassConstantsImpl);
        m_stmt->outputCPP(cg, ar);
        cg.setContext(CodeGenerator::CppImplementation);
      }

      cg.addClass(getClassScope()->getName(), getClassScope());

      if (classScope->isRedeclaring() || classScope->checkHasPropTable(ar)) {
        classScope->outputCPPGlobalTableWrappersImpl(cg, ar);
      }
    }
    break;
  case CodeGenerator::CppFFIDecl:
  case CodeGenerator::CppFFIImpl:
    // do nothing
    break;
  case CodeGenerator::JavaFFI:
    {
      // TODO support PHP namespaces, once HPHP supports it
      string packageName = Option::JavaFFIRootPackage;
      string packageDir = packageName;
      Util::replaceAll(packageDir, ".", "/");

      string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
        packageDir + "/";
      Util::mkdir(outputDir);

      // uses a different cg to generate a separate file for each PHP class
      string clsFile = outputDir + getOriginalName() + ".java";
      std::ofstream fcls(clsFile.c_str());
      CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
      cgCls.setContext(CodeGenerator::JavaFFIInterface);

      cgCls.printf("package %s;\n\n", packageName.c_str());
      cgCls.printf("import hphp.*;\n\n");

      cgCls.printf("public interface %s", getOriginalName().c_str());
      if (m_base) {
        bool first = true;
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && classScope->derivesFrom(ar, intf, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" extends ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName().c_str());
          }
        }
      }

      cgCls.indentBegin(" {\n");
      if (m_stmt) m_stmt->outputCPP(cgCls, ar);
      cgCls.indentEnd("}\n");

      fcls.close();
    }
    break;
  case CodeGenerator::JavaFFICppDecl:
  case CodeGenerator::JavaFFICppImpl:
    // do nothing
    break;
  default:
    ASSERT(false);
    break;
  }
}
Exemplo n.º 19
0
void ClassStatement::outputCPPImpl(CodeGenerator &cg, AnalysisResultPtr ar) {
  ClassScopePtr classScope = m_classScope.lock();
  if (cg.getContext() == CodeGenerator::NoContext) {
    if (classScope->isRedeclaring()) {
      cg_printf("g->%s%s = ClassStaticsPtr(NEW(%s%s)());\n",
                Option::ClassStaticsObjectPrefix,
                cg.formatLabel(m_name).c_str(),
                Option::ClassStaticsPrefix, classScope->getId(cg).c_str());
      cg_printf("g->%s%s = &%s%s;\n",
                Option::ClassStaticsCallbackPrefix,
                cg.formatLabel(m_name).c_str(),
                Option::ClassWrapperFunctionPrefix,
                classScope->getId(cg).c_str());
    }
    if (classScope->isVolatile()) {
      cg_printf("g->CDEC(%s) = true;\n", m_name.c_str());
    }
    const vector<string> &bases = classScope->getBases();
    for (vector<string>::const_iterator it = bases.begin();
         it != bases.end(); ++it) {
      ClassScopePtr base = ar->findClass(*it);
      if (base && base->isVolatile()) {
        cg_printf("checkClassExists(\"%s\", g);\n",
                  base->getOriginalName().c_str());
      }
    }
    return;
  }

  if (cg.getContext() != CodeGenerator::CppForwardDeclaration) {
    printSource(cg);
  }

  ar->pushScope(classScope);
  string clsNameStr = classScope->getId(cg);
  const char *clsName = clsNameStr.c_str();
  bool redeclared = classScope->isRedeclaring();
  switch (cg.getContext()) {
  case CodeGenerator::CppForwardDeclaration:
    if (Option::GenerateCPPMacros) {
      cg_printf("FORWARD_DECLARE_CLASS(%s)\n", clsName);
      if (redeclared) {
        cg_printf("FORWARD_DECLARE_REDECLARED_CLASS(%s)\n", clsName);
      }
    }
    if (m_stmt) {
      cg.setContext(CodeGenerator::CppClassConstantsDecl);
      m_stmt->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::CppForwardDeclaration);
    }
    break;
  case CodeGenerator::CppDeclaration:
    {
      bool system = cg.getOutput() == CodeGenerator::SystemCPP;
      ClassScopePtr parCls;
      if (!m_parent.empty()) {
        parCls = ar->findClass(m_parent);
        if (parCls && parCls->isRedeclaring()) parCls.reset();
      }
      cg_printf("class %s%s", Option::ClassPrefix, clsName);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)) {
        if (!parCls) {
          cg_printf(" : public DynamicObjectData");
        } else {
          cg_printf(" : public %s%s", Option::ClassPrefix,
                    parCls->getId(cg).c_str());
        }
      } else {
        if (classScope->derivesFromRedeclaring()) {
          cg_printf(" : public DynamicObjectData");
        } else if (system) {
          cg_printf(" : public ExtObjectData");
        } else {
          cg_printf(" : public ObjectData");
        }
      }
      if (m_base && Option::UseVirtualDispatch) {
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && !intfClassScope->isRedeclaring() &&
              classScope->derivesDirectlyFrom(ar, intf) &&
              (!parCls || !parCls->derivesFrom(ar, intf, true, false))) {
            string id = intfClassScope->getId(cg);
            cg_printf(", public %s%s", Option::ClassPrefix, id.c_str());
          }
        }
      }
      cg_indentBegin(" {\n");

      if (Option::GenerateCPPMacros) {
        // Get all of this class's ancestors
        vector<string> bases;
        getAllParents(ar, bases);
        // Eliminate duplicates
        sort(bases.begin(), bases.end());
        bases.erase(unique(bases.begin(), bases.end()), bases.end());

        cg_indentBegin("BEGIN_CLASS_MAP(%s)\n",
                       Util::toLower(classScope->getName()).c_str());
        for (unsigned int i = 0; i < bases.size(); i++) {
          cg_printf("PARENT_CLASS(%s)\n", bases[i].c_str());
        }
        if (classScope->derivesFromRedeclaring()) {
          cg_printf("CLASS_MAP_REDECLARED()\n");
        }
        cg_indentEnd("END_CLASS_MAP(%s)\n", clsName);
      }

      if (Option::GenerateCPPMacros) {
        bool dyn = (!parCls && !m_parent.empty()) ||
          classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared;
        bool idyn = parCls && classScope->derivesFromRedeclaring() ==
          ClassScope::IndirectFromRedeclared;
        bool redec = classScope->isRedeclaring();
        if (!classScope->derivesFromRedeclaring()) {
          outputCPPClassDecl(cg, ar, clsName, m_originalName.c_str(),
                             parCls ? parCls->getId(cg).c_str() : "ObjectData");
        } else {
          cg_printf("DECLARE_DYNAMIC_CLASS(%s, %s, %s)\n", clsName,
                    m_originalName.c_str(),
                    dyn || !parCls ? "DynamicObjectData" :
                    parCls->getId(cg).c_str());
        }
        if (system || Option::EnableEval >= Option::LimitedEval) {
          cg_printf("DECLARE_INVOKES_FROM_EVAL\n");
        }
        if (dyn || idyn || redec) {
          if (redec) {
            cg_printf("DECLARE_ROOT;\n");
             if (!dyn && !idyn) {
               cg_printf("private: ObjectData* root;\n");
               cg_printf("public:\n");
               cg_printf("virtual ObjectData *getRoot() { return root; }\n");
             }
          }

          string conInit = ":";
          if (dyn) {
            conInit += "DynamicObjectData(\"" + m_parent + "\", r)";
          } else if (idyn) {
            conInit += string(Option::ClassPrefix) + parCls->getId(cg) +
              "(r?r:this)";
          } else {
            conInit += "root(r?r:this)";
          }

          cg_printf("%s%s(ObjectData* r = NULL)%s {}\n",
                    Option::ClassPrefix, clsName,
                    conInit.c_str());
        }
      }

      cg_printf("void init();\n",
                Option::ClassPrefix, clsName);

      if (classScope->needLazyStaticInitializer()) {
        cg_printf("static GlobalVariables *lazy_initializer"
                  "(GlobalVariables *g);\n");
      }

      classScope->getVariables()->outputCPPPropertyDecl(cg, ar,
          classScope->derivesFromRedeclaring());

      if (!classScope->getAttribute(ClassScope::HasConstructor)) {
        FunctionScopePtr func = classScope->findFunction(ar, "__construct",
                                                         false);
        if (func && !func->isAbstract() && !classScope->isInterface()) {
          ar->pushScope(func);
          func->outputCPPCreateDecl(cg, ar);
          ar->popScope();
        }
      }
      if (classScope->getAttribute(ClassScope::HasDestructor)) {
        cg_printf("public: virtual void destruct();\n");
      }

      // doCall
      if (classScope->getAttribute(ClassScope::HasUnknownMethodHandler)) {
        cg_printf("Variant doCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }
      // doGet
      if (classScope->getAttribute(ClassScope::HasUnknownPropHandler)) {
        cg_printf("Variant doGet(Variant v_name, bool error);\n");
      }


      if (classScope->isRedeclaring() &&
          !classScope->derivesFromRedeclaring()) {
        cg_printf("Variant doRootCall(Variant v_name, Variant v_arguments, "
                  "bool fatal);\n");
      }

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      {
        set<string> done;
        classScope->outputCPPStaticMethodWrappers(cg, ar, done, clsName);
      }

      if (cg.getOutput() == CodeGenerator::SystemCPP &&
          ar->isBaseSysRsrcClass(clsName) &&
          !classScope->hasProperty("rsrc")) {
        cg_printf("public: Variant %srsrc;\n", Option::PropertyPrefix);
      }

      cg_indentEnd("};\n");

      if (redeclared) {
        cg_indentBegin("class %s%s : public ClassStatics {\n",
                       Option::ClassStaticsPrefix, clsName);
        cg_printf("public:\n");
        cg_printf("DECLARE_OBJECT_ALLOCATION(%s%s);\n",
                  Option::ClassStaticsPrefix, clsName);
        cg_printf("%s%s() : ClassStatics(%d) {}\n",
                  Option::ClassStaticsPrefix, clsName,
                  classScope->getRedeclaringId());
        cg_indentBegin("Variant %sgetInit(const char *s, int64 hash = -1) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sgetInit(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sget(const char *s, int64 hash = -1) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sget(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant &%slval(const char* s, int64 hash = -1) {\n",
                  Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%slval(s, hash);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sinvoke(const char *c, const char *s, "
                       "CArrRef params, int64 hash = -1, bool fatal = true) "
                       "{\n",
                  Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sinvoke(c, s, params, hash, fatal);\n",
                  Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Object create(CArrRef params, bool init = true, "
                       "ObjectData* root = NULL) {\n");
        cg_printf("return Object((NEW(%s%s)(root))->"
                  "dynCreate(params, init));\n",
                  Option::ClassPrefix, clsName);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sconstant(const char* s) {\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sconstant(s);\n", Option::ClassPrefix,
                  clsName, Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentBegin("Variant %sinvoke_from_eval(const char *c, "
                       "const char *s, Eval::VariableEnvironment &env, "
                       "const Eval::FunctionCallExpression *call, "
                       "int64 hash = -1, bool fatal = true) "
                       "{\n",
                       Option::ObjectStaticPrefix);
        cg_printf("return %s%s::%sinvoke_from_eval(c, s, env, call, hash, "
                  "fatal);\n",
                  Option::ClassPrefix, clsName,
                  Option::ObjectStaticPrefix);
        cg_indentEnd("}\n");
        cg_indentEnd("};\n");
      }

      classScope->outputCPPGlobalTableWrappersDecl(cg, ar);
    }
    break;
  case CodeGenerator::CppImplementation:
    if (m_stmt) {
      cg.setContext(CodeGenerator::CppClassConstantsImpl);
      m_stmt->outputCPP(cg, ar);
      cg.setContext(CodeGenerator::CppImplementation);
    }

    classScope->outputCPPSupportMethodsImpl(cg, ar);

    if (redeclared) {
      cg_printf("IMPLEMENT_OBJECT_ALLOCATION(%s%s);\n",
                Option::ClassStaticsPrefix, clsName);
    }

    cg_indentBegin("void %s%s::init() {\n",
                   Option::ClassPrefix, clsName);
    if (!m_parent.empty()) {
      if (classScope->derivesFromRedeclaring() ==
          ClassScope::DirectFromRedeclared) {
        cg_printf("parent->init();\n");
      } else {
        cg_printf("%s%s::init();\n", Option::ClassPrefix, m_parent.c_str());
      }
    }
    if (classScope->getVariables()->
        getAttribute(VariableTable::NeedGlobalPointer)) {
      cg.printDeclareGlobals();
    }
    cg.setContext(CodeGenerator::CppConstructor);
    if (m_stmt) m_stmt->outputCPP(cg, ar);

    // This is lame. Exception base class needs to prepare stacktrace outside
    // of its PHP constructor. Every subclass of exception also needs this
    // stacktrace, so we're adding an artificial __init__ in exception.php
    // and calling it here.
    if (m_name == "exception") {
      cg_printf("{CountableHelper h(this); t___init__();}\n");
    }

    cg_indentEnd("}\n");

    if (classScope->needStaticInitializer()) {
      cg_indentBegin("void %s%s::os_static_initializer() {\n",
                     Option::ClassPrefix, clsName);
      cg.printDeclareGlobals();
      cg.setContext(CodeGenerator::CppStaticInitializer);
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg_indentEnd("}\n");
      cg_indentBegin("void %s%s() {\n",
                     Option::ClassStaticInitializerPrefix, clsName);
      cg_printf("%s%s::os_static_initializer();\n",  Option::ClassPrefix,
                clsName);
      cg_indentEnd("}\n");
    }
    if (classScope->needLazyStaticInitializer()) {
      cg_indentBegin("GlobalVariables *%s%s::lazy_initializer("
                     "GlobalVariables *g) {\n", Option::ClassPrefix, clsName);
      cg_indentBegin("if (!g->%s%s) {\n",
                     Option::ClassStaticInitializerFlagPrefix, clsName);
      cg_printf("g->%s%s = true;\n", Option::ClassStaticInitializerFlagPrefix,
                clsName);
      cg.setContext(CodeGenerator::CppLazyStaticInitializer);
      if (m_stmt) m_stmt->outputCPP(cg, ar);
      cg_indentEnd("}\n");
      cg_printf("return g;\n");
      cg_indentEnd("}\n");
    }
    cg.setContext(CodeGenerator::CppImplementation);
    if (m_stmt) m_stmt->outputCPP(cg, ar);

    break;
  case CodeGenerator::CppFFIDecl:
  case CodeGenerator::CppFFIImpl:
    if (m_stmt) m_stmt->outputCPP(cg, ar);
    break;
  case CodeGenerator::JavaFFI:
    {
      if (classScope->isRedeclaring()) break;

      // TODO support PHP namespaces, once HPHP supports it
      string packageName = Option::JavaFFIRootPackage;
      string packageDir = packageName;
      Util::replaceAll(packageDir, ".", "/");

      string outputDir = ar->getOutputPath() + "/" + Option::FFIFilePrefix +
        packageDir + "/";
      Util::mkdir(outputDir);

      // uses a different cg to generate a separate file for each PHP class
      // also, uses the original capitalized class name
      string clsFile = outputDir + getOriginalName() + ".java";
      ofstream fcls(clsFile.c_str());
      CodeGenerator cgCls(&fcls, CodeGenerator::FileCPP);
      cgCls.setContext(CodeGenerator::JavaFFI);

      cgCls.printf("package %s;\n\n", packageName.c_str());
      cgCls.printf("import hphp.*;\n\n");

      printSource(cgCls);

      string clsModifier;
      switch (m_type) {
      case T_CLASS:
        break;
      case T_ABSTRACT:
        clsModifier = "abstract ";
        break;
      case T_FINAL:
        clsModifier = "final ";
        break;
      }
      cgCls.printf("public %sclass %s ", clsModifier.c_str(),
                   getOriginalName().c_str());

      ClassScopePtr parCls;
      if (!m_parent.empty()) parCls = ar->findClass(m_parent);
      if (!m_parent.empty() && classScope->derivesDirectlyFrom(ar, m_parent)
          && parCls && parCls->isUserClass() && !parCls->isRedeclaring()) {
        // system classes are not supported in static FFI translation
        // they shouldn't appear as superclasses as well
        cgCls.printf("extends %s", parCls->getOriginalName().c_str());
      }
      else {
        cgCls.printf("extends HphpObject");
      }
      if (m_base) {
        bool first = true;
        for (int i = 0; i < m_base->getCount(); i++) {
          ScalarExpressionPtr exp =
            dynamic_pointer_cast<ScalarExpression>((*m_base)[i]);
          const char *intf = exp->getString().c_str();
          ClassScopePtr intfClassScope = ar->findClass(intf);
          if (intfClassScope && classScope->derivesFrom(ar, intf, false, false)
           && intfClassScope->isUserClass()) {
            if (first) {
              cgCls.printf(" implements ");
              first = false;
            }
            else {
              cgCls.printf(", ");
            }
            cgCls.printf(intfClassScope->getOriginalName().c_str());
          }
        }
      }

      cgCls.indentBegin(" {\n");

      // constructor for initializing the variant pointer
      cgCls.printf("protected %s(long ptr) { super(ptr); }\n\n",
                   getOriginalName().c_str());

      FunctionScopePtr cons = classScope->findConstructor(ar, true);
      if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) {
        // if not an abstract class and not having an explicit constructor,
        // adds a default constructor
        outputJavaFFIConstructor(cgCls, ar, cons);
      }

      if (m_stmt) m_stmt->outputCPP(cgCls, ar);
      cgCls.indentEnd("}\n");

      fcls.close();
    }
    break;
  case CodeGenerator::JavaFFICppDecl:
  case CodeGenerator::JavaFFICppImpl:
    {
      if (classScope->isRedeclaring()) break;

      if (m_stmt) m_stmt->outputCPP(cg, ar);
      FunctionScopePtr cons = classScope->findConstructor(ar, true);
      if (cons && !cons->isAbstract() || m_type != T_ABSTRACT) {
        outputJavaFFICPPCreator(cg, ar, cons);
      }
    }
    break;
  default:
    ASSERT(false);
    break;
  }

  ar->popScope();
}
TypePtr ObjectPropertyExpression::inferTypes(AnalysisResultPtr ar,
                                             TypePtr type, bool coerce) {
  m_valid = false;

  ConstructPtr self = shared_from_this();
  TypePtr objectType = m_object->inferAndCheck(ar, NEW_TYPE(Object), false);

  if (!m_property->is(Expression::KindOfScalarExpression)) {
    // if dynamic property or method, we have nothing to find out
    if (ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UseDynamicProperty, self);
    }
    m_property->inferAndCheck(ar, Type::String, false);

    // we also lost track of which class variable an expression is about, hence
    // any type inference could be wrong. Instead, we just force variants on
    // all class variables.
    if (m_context & (LValue | RefValue)) {
      ar->forceClassVariants();
    }

    return Type::Variant; // we have to use a variant to hold dynamic value
  }

  ScalarExpressionPtr exp = dynamic_pointer_cast<ScalarExpression>(m_property);
  string name = exp->getString();
  ASSERT(!name.empty());

  m_property->inferAndCheck(ar, Type::String, false);

  ClassScopePtr cls;
  if (objectType && !objectType->getName().empty()) {
    // what object-> has told us
    cls = ar->findExactClass(objectType->getName());
  } else {
    // what ->property has told us
    cls = ar->findClass(name, AnalysisResult::PropertyName);
    if (cls) {
      objectType =
        m_object->inferAndCheck(ar, Type::CreateObjectType(cls->getName()),
                                false);
    }
    if ((m_context & LValue) &&
        objectType && !objectType->is(Type::KindOfObject) &&
                      !objectType->is(Type::KindOfVariant) &&
                      !objectType->is(Type::KindOfSome) &&
                      !objectType->is(Type::KindOfAny)) {
      m_object->inferAndCheck(ar, NEW_TYPE(Object), true);
    }
  }

  if (!cls) {
    if (m_context & (LValue | RefValue)) {
      ar->forceClassVariants(name);
    }
    return Type::Variant;
  }

  const char *accessorName = hasContext(DeepAssignmentLHS) ? "__set" :
    hasContext(ExistContext) ? "__isset" :
    hasContext(UnsetContext) ? "__unset" : "__get";
  if (!cls->implementsAccessor(ar, accessorName)) clearEffect(AccessorEffect);

  // resolved to this class
  int present = 0;
  if (m_context & RefValue) {
    type = Type::Variant;
    coerce = true;
  }

  // use $this inside a static function
  if (m_object->isThis()) {
    FunctionScopePtr func = ar->getFunctionScope();
    if (func->isStatic()) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                   self);
      }
      m_actualType = Type::Variant;
      return m_actualType;
    }
  }

  TypePtr ret;
  if (!cls->derivesFromRedeclaring()) { // Have to use dynamic.
    ret = cls->checkProperty(name, type, coerce, ar, self, present);
    // Private only valid if in the defining class
    if (present && (getOriginalScope(ar) == cls ||
                    !(present & VariableTable::VariablePrivate))) {
      m_valid = true;
      m_static = present & VariableTable::VariableStatic;
      if (m_static) {
        ar->getScope()->getVariables()->
          setAttribute(VariableTable::NeedGlobalPointer);
      }
      m_class = cls;
    }
  }

  // get() will return Variant
  if (!m_valid || !m_object->getType()->isSpecificObject()) {
    m_actualType = Type::Variant;
    return m_actualType;
  }

  clearEffect(AccessorEffect);

  if (ar->getPhase() == AnalysisResult::LastInference) {
    if (!(m_context & ObjectContext)) {
      m_object->clearContext(Expression::LValue);
    }
    setContext(Expression::NoLValueWrapper);
  }
  return ret;
}
Exemplo n.º 21
0
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;
}
Exemplo n.º 22
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->addDeclaredSymbol(m_name, shared_from_this());
  }

  if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
    if (FunctionScopePtr func = getFunctionScope()) {
      if (m_name == "this" && func->mayContainThis()) {
        func->setContainsThis();
        m_this = true;
        if (!hasContext(ObjectContext)) {
          bool unset = hasAllContext(UnsetContext | LValue);
          func->setContainsBareThis(
            true,
            hasAnyContext(RefValue | RefAssignmentLHS) ||
            m_sym->isRefClosureVar() || unset);
          if (variables->getAttribute(VariableTable::ContainsDynamicVariable)) {
            ClassScopePtr cls = getClassScope();
            TypePtr t = !cls || 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_this) {
      if (!m_sym->isSystem() &&
          !(getContext() &
            (LValue|RefValue|RefParameter|UnsetContext|ExistContext)) &&
          m_sym->getDeclaration().get() == this) {
        assert(!m_sym->isParameter());

        if (!variables->getAttribute(VariableTable::ContainsLDynamicVariable) &&
            !getScope()->is(BlockScope::ClassScope)) {
          if (getScope()->inPseudoMain()) {
            Compiler::Error(Compiler::UseUndeclaredGlobalVariable,
                            shared_from_this());
          } else if (!m_sym->isClosureVar()) {
            Compiler::Error(Compiler::UseUndeclaredVariable,
                            shared_from_this());
          }
        }
      }
      // check function parameter that can occur in lval context
      if (m_sym->isParameter() &&
          m_context & (LValue | RefValue | DeepReference |
                       UnsetContext | InvokeArgument | OprLValue |
                       DeepOprLValue)) {
        m_sym->setLvalParam();
      }
    }
  }
}
Exemplo n.º 23
0
void MethodStatement::onParseRecur(AnalysisResultConstPtr ar,
                                   ClassScopePtr classScope) {

  FunctionScopeRawPtr fs = getFunctionScope();
  const bool isNative = fs->isNative();
  if (m_modifiers) {
    if ((m_modifiers->isExplicitlyPublic() +
         m_modifiers->isProtected() +
         m_modifiers->isPrivate()) > 1) {
      m_modifiers->parseTimeFatal(
        Compiler::InvalidAttribute,
        "%s: method %s::%s()",
        Strings::PICK_ACCESS_MODIFIER,
        classScope->getOriginalName().c_str(),
        getOriginalName().c_str()
      );
    }

    if (classScope->isInterface()) {
      if (m_modifiers->isProtected() || m_modifiers->isPrivate() ||
          m_modifiers->isAbstract()  || m_modifiers->isFinal() ||
          isNative) {
        m_modifiers->parseTimeFatal(
          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(
          Compiler::InvalidAttribute,
          Strings::ASYNC_WITHOUT_BODY,
          "interface", classScope->getOriginalName().c_str(),
          getOriginalName().c_str()
        );
      }
    }
    if (m_modifiers->isAbstract()) {
      if (m_modifiers->isPrivate() || m_modifiers->isFinal() || isNative) {
        m_modifiers->parseTimeFatal(
          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(Compiler::InvalidAttribute,
                                    "Class %s contains abstract method %s and "
                                    "must therefore be declared abstract",
                                    classScope->getOriginalName().c_str(),
                                    getOriginalName().c_str());
      }
      if (getStmts()) {
        parseTimeFatal(Compiler::InvalidAttribute,
                       "Abstract method %s::%s() cannot contain body",
                       classScope->getOriginalName().c_str(),
                       getOriginalName().c_str());
      }
      if (m_modifiers->isAsync()) {
        m_modifiers->parseTimeFatal(
          Compiler::InvalidAttribute,
          Strings::ASYNC_WITHOUT_BODY,
          "abstract", classScope->getOriginalName().c_str(),
          getOriginalName().c_str()
        );
      }
    }
    if (isNative) {
      if (getStmts()) {
        parseTimeFatal(Compiler::InvalidAttribute,
                       "Native method %s::%s() cannot contain body",
                       classScope->getOriginalName().c_str(),
                       getOriginalName().c_str());
      }
      if (!m_retTypeAnnotation) {
        parseTimeFatal(Compiler::InvalidAttribute,
                       "Native method %s::%s() must have a return type hint",
                       classScope->getOriginalName().c_str(),
                       getOriginalName().c_str());
      }
    }
  }
  if ((!m_modifiers || !m_modifiers->isAbstract()) &&
      !getStmts() && !classScope->isInterface() && !isNative) {
    parseTimeFatal(Compiler::InvalidAttribute,
                   "Non-abstract method %s::%s() must contain body",
                   classScope->getOriginalName().c_str(),
                   getOriginalName().c_str());
  }

  classScope->addFunction(ar, fs);

  m_className = classScope->getName();
  m_originalClassName = classScope->getOriginalName();

  setSpecialMethod(classScope);

  if (Option::DynamicInvokeFunctions.find(getFullName()) !=
      Option::DynamicInvokeFunctions.end()) {
    fs->setDynamicInvoke();
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      param->parseHandler(classScope);
      if (isNative && !param->hasUserType()) {
        parseTimeFatal(Compiler::InvalidAttribute,
                       "Native method calls must have type hints on all args");
      }
    }
  }
  FunctionScope::RecordFunctionInfo(m_name, fs);
}
Exemplo n.º 24
0
void MethodStatement::onParseRecur(AnalysisResultConstPtr ar,
                                   ClassScopePtr classScope) {

  FunctionScopeRawPtr fs = getFunctionScope();
  const bool isNative = fs->isNative();
  if (m_modifiers) {
    if ((m_modifiers->isExplicitlyPublic() +
         m_modifiers->isProtected() +
         m_modifiers->isPrivate()) > 1) {
      m_modifiers->parseTimeFatal(
        Compiler::InvalidAttribute,
        Strings::PICK_ACCESS_MODIFIER
      );
    }

    if (m_modifiers->hasDuplicates()) {
      m_modifiers->parseTimeFatal(
        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(
          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(
          Compiler::InvalidAttribute,
          Strings::ASYNC_WITHOUT_BODY,
          "interface", classScope->getOriginalName().c_str(),
          getOriginalName().c_str()
        );
      }
      if (getStmts()) {
        getStmts()->parseTimeFatal(
          Compiler::InvalidMethodDefinition,
          "Interface method %s::%s() cannot contain body",
          classScope->getOriginalName().c_str(),
          getOriginalName().c_str());
      }
    }
    if (m_modifiers->isAbstract()) {
      if (m_modifiers->isPrivate() || m_modifiers->isFinal() || isNative) {
        m_modifiers->parseTimeFatal(
          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(Compiler::InvalidAttribute,
                                    "Class %s contains abstract method %s and "
                                    "must therefore be declared abstract",
                                    classScope->getOriginalName().c_str(),
                                    getOriginalName().c_str());
      }
      if (getStmts()) {
        parseTimeFatal(Compiler::InvalidAttribute,
                       "Abstract method %s::%s() cannot contain body",
                       classScope->getOriginalName().c_str(),
                       getOriginalName().c_str());
      }
      if (m_modifiers->isAsync()) {
        m_modifiers->parseTimeFatal(
          Compiler::InvalidAttribute,
          Strings::ASYNC_WITHOUT_BODY,
          "abstract", classScope->getOriginalName().c_str(),
          getOriginalName().c_str()
        );
      }
    }
    if (!m_modifiers->isStatic() && classScope->isStaticUtil()) {
      m_modifiers->parseTimeFatal(
        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(Compiler::InvalidAttribute,
                       "Native method %s::%s() cannot contain body",
                       classScope->getOriginalName().c_str(),
                       getOriginalName().c_str());
      }
      auto is_ctordtor = (m_name == "__construct") || (m_name == "__destruct");
      if (!m_retTypeAnnotation && !is_ctordtor) {
        parseTimeFatal(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(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(Compiler::InvalidAttribute,
                   "Non-abstract method %s::%s() must contain body",
                   classScope->getOriginalName().c_str(),
                   getOriginalName().c_str());
  }

  classScope->addFunction(ar, fs);

  m_className = classScope->getName();
  m_originalClassName = classScope->getOriginalName();

  setSpecialMethod(classScope);

  if (Option::DynamicInvokeFunctions.find(getFullName()) !=
      Option::DynamicInvokeFunctions.end()) {
    fs->setDynamicInvoke();
  }
  if (m_params) {
    auto nParams = m_params->getCount();
    for (int i = 0; i < nParams; i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      param->parseHandler(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(Compiler::InvalidAttribute,
                       "Native method calls must have type hints on all args");
      }
    }
  }
  FunctionScope::RecordFunctionInfo(m_name, fs);
}
Exemplo n.º 25
0
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;
}
Exemplo n.º 26
0
TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
                                          bool coerce) {
  reset();

  ConstructPtr self = shared_from_this();

  // handling define("CONSTANT", ...);
  if (m_className.empty()) {
    if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        if (!varName.empty()) {
          ExpressionPtr value = (*m_params)[1];
          TypePtr varType = value->inferAndCheck(ar, NEW_TYPE(Some), false);
          ar->getDependencyGraph()->
            addParent(DependencyGraph::KindOfConstant,
                      ar->getName(), varName, self);
          ConstantTablePtr constants =
            ar->findConstantDeclarer(varName)->getConstants();
          if (constants != ar->getConstants()) {
            if (value && !value->isScalar()) {
              constants->setDynamic(ar, varName);
              varType = Type::Variant;
            }
            if (constants->isDynamic(varName)) {
              m_dynamicConstant = true;
              ar->getScope()->getVariables()->
                setAttribute(VariableTable::NeedGlobalPointer);
            } else {
              constants->setType(ar, varName, varType, true);
            }
            // in case the old 'value' has been optimized
            constants->setValue(ar, varName, value);
          }
          return checkTypesImpl(ar, type, Type::Boolean, coerce);
        }
      }
      if (varName.empty() && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::BadDefine, self);
      }
    } else if (m_type == ExtractFunction) {
      ar->getScope()->getVariables()->forceVariants(ar);
    }
  }

  FunctionScopePtr func;

  // avoid raising both MissingObjectContext and UnknownFunction
  bool errorFlagged = false;

  if (m_className.empty()) {
    func = ar->findFunction(m_name);
  } else {
    ClassScopePtr cls = ar->resolveClass(m_className);
    if (cls && cls->isVolatile()) {
      ar->getScope()->getVariables()
        ->setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!cls || cls->isRedeclaring()) {
      if (cls) {
        m_redeclaredClass = true;
      }
      if (!cls && ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::UnknownClass, self);
      }
      if (m_params) {
        m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
      }
      return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_derivedFromRedeclaring = cls->derivesFromRedeclaring();
    m_validClass = true;

    if (m_name == "__construct") {
      // if the class is known, php will try to identify class-name ctor
      func = cls->findConstructor(ar, true);
    }
    else {
      func = cls->findFunction(ar, m_name, true, true);
    }

    if (func && !func->isStatic()) {
      ClassScopePtr clsThis = ar->getClassScope();
      FunctionScopePtr funcThis = ar->getFunctionScope();
      if (!clsThis ||
          (clsThis->getName() != m_className &&
           !clsThis->derivesFrom(ar, m_className)) ||
          funcThis->isStatic()) {
        // set the method static to avoid "unknown method" runtime exception
        if (Option::StaticMethodAutoFix && !func->containsThis()) {
          func->setStatic();
        }
        if (ar->isFirstPass()) {
          ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                     self);
          errorFlagged = true;
        }
        func.reset();
      }
    }
  }
  if (!func || func->isRedeclaring()) {
    if (func) {
      m_redeclared = true;
      ar->getScope()->getVariables()->
        setAttribute(VariableTable::NeedGlobalPointer);
    }
    if (!func && !errorFlagged && ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UnknownFunction, self);
    }
    if (m_params) {
      if (func) {
        FunctionScope::RefParamInfoPtr info =
          FunctionScope::GetRefParamInfo(m_name);
        ASSERT(info);
        for (int i = m_params->getCount(); i--; ) {
          if (info->isRefParam(i)) {
            m_params->markParam(i, canInvokeFewArgs());
          }
        }
      }
      m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }
  m_builtinFunction = !func->isUserFunction();

  if (m_redeclared) {
    if (m_params) {
      m_params->inferAndCheck(ar, NEW_TYPE(Some), false);
    }
    return checkTypesImpl(ar, type, type, coerce);
  }

  CHECK_HOOK(beforeSimpleFunctionCallCheck);

  m_valid = true;
  type = checkParamsAndReturn(ar, type, coerce, func);

  if (!m_valid && m_params) {
    m_params->markParams(false);
  }

  CHECK_HOOK(afterSimpleFunctionCallCheck);

  return type;
}
Exemplo n.º 27
0
TypePtr Type::Coerce(AnalysisResultConstPtr ar, TypePtr type1, TypePtr type2) {
  if (SameType(type1, type2)) return type1;
  if (type1->m_kindOf == KindOfVariant ||
      type2->m_kindOf == KindOfVariant) return Type::Variant;
  if (type1->m_kindOf > type2->m_kindOf) {
    TypePtr tmp = type1;
    type1 = type2;
    type2 = tmp;
  }
  if (type1->m_kindOf == KindOfVoid &&
      (type2->m_kindOf == KindOfString ||
       type2->m_kindOf == KindOfArray ||
       type2->m_kindOf == KindOfObject)) {
    return type2;
  }
  if (type2->m_kindOf == KindOfSome ||
      type2->m_kindOf == KindOfAny) return type1;

  if (type2->m_kindOf & KindOfAuto) {
    if (type1->mustBe(type2->m_kindOf & ~KindOfAuto)) {
      if (!(type1->m_kindOf & Type::KindOfString)) {
        return type1;
      }
      if (type2->m_kindOf == KindOfAutoSequence) {
        return Type::Sequence;
      }
      return GetType((KindOf)(type2->m_kindOf & ~KindOfAuto));
    }
    return Type::Variant;
  }

  if (type1->mustBe(KindOfInteger)) {
    if (type2->mustBe(KindOfInteger)) {
      return type2;
    } else if (type2->mustBe(KindOfDouble)) {
      return Type::Numeric;
    }
  }

  if (type1->mustBe(Type::KindOfObject) &&
      type2->mustBe(Type::KindOfObject)) {
    if (type1->m_name.empty()) return type1;
    if (type2->m_name.empty()) return type2;
    ClassScopePtr cls1 = ar->findClass(type1->m_name);
    if (cls1 && !cls1->isRedeclaring() &&
        cls1->derivesFrom(ar, type2->m_name, true, false)) {
      return type2;
    }
    ClassScopePtr cls2 = ar->findClass(type2->m_name);
    if (cls2 && !cls2->isRedeclaring() &&
        cls2->derivesFrom(ar, type1->m_name, true, false)) {
      return type1;
    }
    if (cls1 && cls2 &&
        !cls1->isRedeclaring() && !cls2->isRedeclaring()) {
      ClassScopePtr parent =
        ClassScope::FindCommonParent(ar, type1->m_name,
                                         type2->m_name);
      if (parent) {
        return Type::CreateObjectType(parent->getName());
      }
    }
    return Type::Object;
  }

  if (type1->mustBe(type2->m_kindOf)) {
    return type2;
  }

  CT_ASSERT(Type::KindOfString < Type::KindOfArray);
  if (type1->m_kindOf == Type::KindOfString &&
      type2->m_kindOf == Type::KindOfArray) {
    return Type::Sequence;
  }

  return Type::Variant;
}
Exemplo n.º 28
0
void MethodStatement::onParseRecur(AnalysisResultConstPtr ar,
                                   ClassScopePtr classScope) {

  if (m_modifiers) {
    if (classScope->isInterface()) {
      if (m_modifiers->isProtected() || m_modifiers->isPrivate() ||
          m_modifiers->isAbstract()  || m_modifiers->isFinal()) {
        m_modifiers->parseTimeFatal(
          Compiler::InvalidAttribute,
          "Access type for interface method %s::%s() must be omitted",
          classScope->getOriginalName().c_str(), getOriginalName().c_str());
      }
    }
    if (m_modifiers->isAbstract()) {
      if (m_modifiers->isPrivate() || m_modifiers->isFinal()) {
        m_modifiers->parseTimeFatal(
          Compiler::InvalidAttribute,
          "Cannot declare abstract method %s::%s() %s",
          classScope->getOriginalName().c_str(),
          getOriginalName().c_str(),
          m_modifiers->isPrivate() ? "private" : "final");
      }
      if (!classScope->isInterface() && !classScope->isAbstract()) {
        /* note that classScope->isAbstract() returns true for traits */
        m_modifiers->parseTimeFatal(Compiler::InvalidAttribute,
                                    "Class %s contains abstract method %s and "
                                    "must therefore be declared abstract",
                                    classScope->getOriginalName().c_str(),
                                    getOriginalName().c_str());
      }
      if (getStmts()) {
        parseTimeFatal(Compiler::InvalidAttribute,
                       "Abstract method %s::%s() cannot contain body",
                       classScope->getOriginalName().c_str(),
                       getOriginalName().c_str());
      }
    }
  }
  if ((!m_modifiers || !m_modifiers->isAbstract()) &&
      !getStmts() && !classScope->isInterface()) {
    parseTimeFatal(Compiler::InvalidAttribute,
                   "Non-abstract method %s::%s() must contain body",
                   classScope->getOriginalName().c_str(),
                   getOriginalName().c_str());
  }

  FunctionScopeRawPtr fs = getFunctionScope();

  classScope->addFunction(ar, fs);

  m_className = classScope->getName();
  m_originalClassName = classScope->getOriginalName();

  setSpecialMethod(classScope);

  if (Option::DynamicInvokeFunctions.find(getFullName()) !=
      Option::DynamicInvokeFunctions.end()) {
    fs->setDynamicInvoke();
  }
  if (m_params) {
    for (int i = 0; i < m_params->getCount(); i++) {
      ParameterExpressionPtr param =
        dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
      param->parseHandler(classScope);
    }
  }
  FunctionScope::RecordFunctionInfo(m_name, fs);
}
Exemplo n.º 29
0
void SimpleFunctionCall::outputCPPImpl(CodeGenerator &cg,
                                       AnalysisResultPtr ar) {
  bool linemap = outputLineMap(cg, ar, true);

  if (!m_lambda.empty()) {
    cg.printf("\"%s\"", m_lambda.c_str());
    if (linemap) cg.printf(")");
    return;
  }

  if (m_className.empty()) {
    if (m_type == DefineFunction && m_params && m_params->getCount() >= 2) {
      ScalarExpressionPtr name =
        dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
      string varName;
      if (name) {
        varName = name->getIdentifier();
        ExpressionPtr value = (*m_params)[1];
        if (varName.empty()) {
          cg.printf("throw_fatal(\"bad define\")");
        } else if (m_dynamicConstant) {
          cg.printf("g->declareConstant(\"%s\", g->%s%s, ",
                    varName.c_str(), Option::ConstantPrefix,
                    varName.c_str());
          value->outputCPP(cg, ar);
          cg.printf(")");
        } else {
          bool needAssignment = true;
          bool isSystem = ar->getConstants()->isSystem(varName);
          if (isSystem ||
              ((!ar->isConstantRedeclared(varName)) && value->isScalar())) {
            needAssignment = false;
          }
          if (needAssignment) {
            cg.printf("%s%s = ", Option::ConstantPrefix, varName.c_str());
            value->outputCPP(cg, ar);
          }
        }
      } else {
        cg.printf("throw_fatal(\"bad define\")");
      }
      if (linemap) cg.printf(")");
      return;
    }
    if (m_name == "func_num_args") {
      cg.printf("num_args");
      if (linemap) cg.printf(")");
      return;
    }

    switch (m_type) {
    case VariableArgumentFunction:
      {
        FunctionScopePtr func =
          dynamic_pointer_cast<FunctionScope>(ar->getScope());
        if (func) {
          cg.printf("%s(", m_name.c_str());
          func->outputCPPParamsCall(cg, ar, true);
          if (m_params) {
            cg.printf(",");
            m_params->outputCPP(cg, ar);
          }
          cg.printf(")");
          if (linemap) cg.printf(")");
          return;
        }
      }
      break;
    case FunctionExistsFunction:
    case ClassExistsFunction:
    case InterfaceExistsFunction:
      {
        bool literalString = false;
        string symbol;
        if (m_params && m_params->getCount() == 1) {
          ExpressionPtr value = (*m_params)[0];
          if (value->isScalar()) {
            ScalarExpressionPtr name =
              dynamic_pointer_cast<ScalarExpression>(value);
            if (name && name->isLiteralString()) {
              literalString = true;
              symbol = name->getLiteralString();
            }
          }
        }
        if (literalString) {
          switch (m_type) {
          case FunctionExistsFunction:
            {
              const std::string &lname = Util::toLower(symbol);
              bool dynInvoke = Option::DynamicInvokeFunctions.find(lname) !=
                Option::DynamicInvokeFunctions.end();
              if (!dynInvoke) {
                FunctionScopePtr func = ar->findFunction(lname);
                if (func) {
                  if (!func->isDynamic()) {
                    if (func->isRedeclaring()) {
                      const char *name = func->getName().c_str();
                      cg.printf("(%s->%s%s != invoke_failed_%s)",
                                cg.getGlobals(ar), Option::InvokePrefix,
                                name, name);
                      break;
                    }
                    cg.printf("true");
                    break;
                  }
                } else {
                  cg.printf("false");
                  break;
                }
              }
              cg.printf("f_function_exists(\"%s\")", lname.c_str());
            }
            break;
          case ClassExistsFunction:
            {
              ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
              if (cls && !cls->isInterface()) {
                const char *name = cls->getName().c_str();
                cg.printf("f_class_exists(\"%s\")", name);
              } else {
                cg.printf("false");
              }
            }
            break;
          case InterfaceExistsFunction:
            {
              ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
              if (cls && cls->isInterface()) {
                const char *name = cls->getName().c_str();
                cg.printf("f_interface_exists(\"%s\")", name);
              } else {
                cg.printf("false");
              }
            }
            break;
          default:
            break;
          }
          if (linemap) cg.printf(")");
          return;
        }
      }
      break;
    case GetDefinedVarsFunction:
      cg.printf("get_defined_vars(variables)");
      if (linemap) cg.printf(")");
      return;
    default:
      break;
    }
  }

  outputCPPParamOrderControlled(cg, ar);
  if (linemap) cg.printf(")");
}
Exemplo n.º 30
0
bool FunctionScope::isConstructor(ClassScopePtr cls) const {
  return m_stmt && cls
    && (getName() == "__construct"
     || (cls->classNameCtor() && getName() == cls->getName()));
}