Exemplo n.º 1
0
void Expression::setDynamicByIdentifier(AnalysisResultPtr ar,
                                        const std::string &value) {
  string id = toLower(value);
  size_t c = id.find("::");
  FunctionScopePtr fi;
  ClassScopePtr ci;
  if (c != 0 && c != string::npos && c+2 < id.size()) {
    string cl = id.substr(0, c);
    string fn = id.substr(c+2);
    if (IsIdentifier(cl) && IsIdentifier(fn)) {
      ci = ar->findClass(cl);
      if (ci) {
        fi = ci->findFunction(ar, fn, false);
        if (fi) fi->setDynamic();
      }
    }
  } else if (IsIdentifier(id)) {
    fi = ar->findFunction(id);
    if (fi) fi->setDynamic();
    ClassScopePtr ci = ar->findClass(id, AnalysisResult::MethodName);
    if (ci) {
      fi = ci->findFunction(ar, id, false);
      if (fi) fi->setDynamic();
    }
  }
}
Exemplo n.º 2
0
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);
  }
}
Exemplo n.º 3
0
ClassScopePtr AnalysisResult::findClass(const std::string &name,
                                        FindClassBy by) {
  AnalysisResultPtr ar = shared_from_this();
  if (by == PropertyName) return ClassScopePtr();

  string lname = toLower(name);
  if (by == MethodName) {
    StringToClassScopePtrVecMap::iterator iter =
      m_methodToClassDecs.find(lname);
    if (iter != m_methodToClassDecs.end()) {
      if (iter->second.size() == 1) {
        iter->second[0]->findFunction(ar, lname, true)->setDynamic();
        return ClassScopePtr();
      } else {
        // The call to findClass by method name means all these
        // same-named methods should be dynamic since there will
        // be an invoke to call one of them.
        for (ClassScopePtr cls: iter->second) {
          FunctionScopePtr func = cls->findFunction(ar, lname, true);
          // Something fishy here
          if (func) {
            func->setDynamic();
          }
        }
        iter->second.clear();
      }
    }
  } else {
    return findClass(name);
  }
  return ClassScopePtr();
}
Exemplo n.º 4
0
void MethodStatement::analyzeProgramImpl(AnalysisResultPtr ar) {
  FunctionScopePtr funcScope = m_funcScope.lock();

  // registering myself as a parent in dependency graph, so that
  // (1) we can tell orphaned parents
  // (2) overwrite non-master copy of function declarations
  if (ar->isFirstPass()) {
    ar->getDependencyGraph()->addParent(DependencyGraph::KindOfFunctionCall,
                                        "", getFullName(), shared_from_this());
    if (Option::AllDynamic || hasHphpNote("Dynamic") ||
        funcScope->isSepExtension() ||
        BuiltinSymbols::IsDeclaredDynamic(m_name) ||
        Option::IsDynamicFunction(m_method, m_name)) {
      funcScope->setDynamic();
    }
    if (hasHphpNote("Volatile")) funcScope->setVolatile();
  }

  funcScope->setIncludeLevel(ar->getIncludeLevel());
  ar->pushScope(funcScope);
  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->isFirstPass()) {
    if (!funcScope->isStatic() && ar->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(NEW_TYPE(Object));
      funcScope->getVariables()->add("this", tp, true, ar, shared_from_this(),
                                     ModifierExpressionPtr());
    }
    FunctionScope::RecordRefParamInfo(m_name, funcScope);
  }
  ar->popScope();
}
Exemplo n.º 5
0
void ClassScope::setStaticDynamic(AnalysisResultConstPtr ar) {
  for (FunctionScopePtrVec::const_iterator iter =
         m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) {
    FunctionScopePtr fs = *iter;
    if (fs->isStatic()) fs->setDynamic();
  }
  if (!m_parent.empty()) {
    if (derivesFromRedeclaring() == Derivation::Redeclaring) {
      const ClassScopePtrVec &parents = ar->findRedeclaredClasses(m_parent);
      for (ClassScopePtr cl: parents) {
        cl->setStaticDynamic(ar);
      }
    } else {
      ClassScopePtr parent = ar->findClass(m_parent);
      if (parent) {
        parent->setStaticDynamic(ar);
      }
    }
  }
}
Exemplo n.º 6
0
void ClassScope::setDynamic(AnalysisResultConstPtr ar,
                            const std::string &name) {
  StringToFunctionScopePtrMap::const_iterator iter =
    m_functions.find(name);
  if (iter != m_functions.end()) {
    FunctionScopePtr fs = iter->second;
    fs->setDynamic();
  } else if (!m_parent.empty()) {
    if (derivesFromRedeclaring() == Derivation::Redeclaring) {
      const ClassScopePtrVec &parents = ar->findRedeclaredClasses(m_parent);
      for (ClassScopePtr cl: parents) {
        cl->setDynamic(ar, name);
      }
    } else {
      ClassScopePtr parent = ar->findClass(m_parent);
      if (parent) {
        parent->setDynamic(ar, name);
      }
    }
  }
}
TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
                                              TypePtr type, bool coerce) {
  reset();

  ConstructPtr self = shared_from_this();
  TypePtr objectType = m_object->inferAndCheck(ar, Type::Object, false);
  m_valid = true;
  m_bindClass = true;

  if (m_name.empty()) {
    m_nameExp->inferAndCheck(ar, Type::String, false);
    setInvokeParams(ar);
    // we have to use a variant to hold dynamic value
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }

  ClassScopePtr cls;
  if (objectType && !objectType->getName().empty()) {
    if (m_classScope && !strcasecmp(objectType->getName().c_str(),
                                    m_classScope->getName().c_str())) {
      cls = m_classScope;
    } else {
      cls = ar->findExactClass(shared_from_this(), objectType->getName());
    }
  }

  if (!cls) {
    if (getScope()->isFirstPass()) {
      // call resolveClass to mark functions as dynamic
      // but we cant do anything else with the result.
      resolveClass(ar, m_name);
      if (!ar->classMemberExists(m_name, AnalysisResult::MethodName)) {
        Compiler::Error(Compiler::UnknownObjectMethod, self);
      }
    }

    m_classScope.reset();
    m_funcScope.reset();

    setInvokeParams(ar);
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }

  if (m_classScope != cls) {
    m_classScope = cls;
    m_funcScope.reset();
  }

  FunctionScopePtr func = m_funcScope;
  if (!func) {
    func = cls->findFunction(ar, m_name, true, true);
    if (!func) {
      if (!cls->hasAttribute(ClassScope::HasUnknownMethodHandler, ar)) {
        if (ar->classMemberExists(m_name, AnalysisResult::MethodName)) {
          setDynamicByIdentifier(ar, m_name);
        } else {
          Compiler::Error(Compiler::UnknownObjectMethod, self);
        }
      }

      m_valid = false;
      setInvokeParams(ar);
      return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_funcScope = func;
    func->addCaller(getScope());
  }

  bool valid = true;
  m_bindClass = func->isStatic();

  // use $this inside a static function
  if (m_object->isThis()) {
    FunctionScopePtr localfunc = getFunctionScope();
    if (localfunc->isStatic()) {
      if (getScope()->isFirstPass()) {
        Compiler::Error(Compiler::MissingObjectContext, self);
      }
      valid = false;
    }
  }

  // invoke() will return Variant
  if (!m_object->getType()->isSpecificObject() ||
      (func->isVirtual() && !func->isPerfectVirtual())) {
    valid = false;
  }

  if (!valid) {
    setInvokeParams(ar);
    checkTypesImpl(ar, type, Type::Variant, coerce);
    m_valid = false; // so we use invoke() syntax
    func->setDynamic();
    return m_actualType;
  }

  return checkParamsAndReturn(ar, type, coerce, func, false);
}
TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
                                              TypePtr type, bool coerce) {
  reset();

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

  if (m_name.empty()) {
    // if dynamic property or method, we have nothing to find out
    if (ar->isFirstPass()) {
      ar->getCodeError()->record(self, CodeError::UseDynamicMethod, self);
    }
    m_nameExp->inferAndCheck(ar, Type::String, false);
    setInvokeParams(ar);
    // we have to use a variant to hold dynamic value
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }

  ClassScopePtr cls = m_classScope;
  if (objectType && !objectType->getName().empty()) {
    cls = ar->findExactClass(objectType->getName());
  }

  if (!cls) {
    if (ar->isFirstPass()) {
      // call resolveClass to mark functions as dynamic
      // but we cant do anything else with the result.
      resolveClass(ar, m_name);
      if (!ar->classMemberExists(m_name, AnalysisResult::MethodName)) {
        ar->getCodeError()->record(self, CodeError::UnknownObjectMethod, self);
      }
    }

    m_classScope.reset();
    m_funcScope.reset();

    setInvokeParams(ar);
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }

  if (m_classScope != cls) {
    m_classScope = cls;
    m_funcScope.reset();
  }

  FunctionScopePtr func = m_funcScope;
  if (!func) {
    func = cls->findFunction(ar, m_name, true, true);
    if (!func) {
      if (!cls->hasAttribute(ClassScope::HasUnknownMethodHandler, ar)) {
        if (ar->classMemberExists(m_name, AnalysisResult::MethodName)) {
          // TODO: we could try to find out class derivation is present...
          ar->getCodeError()->record(self,
                                     CodeError::DerivedObjectMethod, self);
          // we have to make sure the method is in invoke list
          setDynamicByIdentifier(ar, m_name);
        } else {
          ar->getCodeError()->record(self,
                                     CodeError::UnknownObjectMethod, self);
        }
      }

      m_valid = false;
      setInvokeParams(ar);
      return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_funcScope = func;
  }

  bool valid = true;
  m_bindClass = func->isStatic();

  // use $this inside a static function
  if (m_object->isThis()) {
    FunctionScopePtr localfunc = ar->getFunctionScope();
    if (localfunc->isStatic()) {
      if (ar->isFirstPass()) {
        ar->getCodeError()->record(self, CodeError::MissingObjectContext,
                                   self);
      }
      valid = false;
    }
  }

  // invoke() will return Variant
  if (func->isVirtual() || !m_object->getType()->isSpecificObject()) {
    valid = false;
  }

  if (!valid) {
    setInvokeParams(ar);
    checkTypesImpl(ar, type, Type::Variant, coerce);
    m_valid = false; // so we use invoke() syntax
    func->setDynamic();
    return m_actualType;
  }

  return checkParamsAndReturn(ar, type, coerce, func);
}
TypePtr ObjectMethodExpression::inferAndCheck(AnalysisResultPtr ar,
                                              TypePtr type, bool coerce) {
  assert(type);
  IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
  resetTypes();
  reset();

  ConstructPtr self = shared_from_this();
  TypePtr objectType = m_object->inferAndCheck(ar, Type::Some, false);
  m_valid = true;
  m_bindClass = true;

  if (m_name.empty()) {
    m_nameExp->inferAndCheck(ar, Type::Some, false);
    setInvokeParams(ar);
    // we have to use a variant to hold dynamic value
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }

  ClassScopePtr cls;
  if (objectType && !objectType->getName().empty()) {
    if (m_classScope && !strcasecmp(objectType->getName().c_str(),
                                    m_classScope->getName().c_str())) {
      cls = m_classScope;
    } else {
      cls = ar->findExactClass(shared_from_this(), objectType->getName());
    }
  }

  if (!cls) {
    m_classScope.reset();
    m_funcScope.reset();

    m_valid = false;
    setInvokeParams(ar);
    return checkTypesImpl(ar, type, Type::Variant, coerce);
  }

  if (m_classScope != cls) {
    m_classScope = cls;
    m_funcScope.reset();
  }

  FunctionScopePtr func = m_funcScope;
  if (!func) {
    func = cls->findFunction(ar, m_name, true, true);
    if (!func) {
      if (!cls->isTrait() &&
          !cls->getAttribute(ClassScope::MayHaveUnknownMethodHandler) &&
          !cls->getAttribute(ClassScope::HasUnknownMethodHandler) &&
          !cls->getAttribute(ClassScope::InheritsUnknownMethodHandler)) {
        if (ar->classMemberExists(m_name, AnalysisResult::MethodName)) {
          if (!Option::AllDynamic) {
            setDynamicByIdentifier(ar, m_name);
          }
        } else {
          Compiler::Error(Compiler::UnknownObjectMethod, self);
        }
      }

      m_valid = false;
      setInvokeParams(ar);
      return checkTypesImpl(ar, type, Type::Variant, coerce);
    }
    m_funcScope = func;
    func->addCaller(getScope(), !type->is(Type::KindOfAny));
  }

  bool valid = true;
  m_bindClass = func->isStatic();

  // use $this inside a static function
  if (m_object->isThis()) {
    FunctionScopePtr localfunc = getFunctionScope();
    if (localfunc->isStatic()) {
      if (getScope()->isFirstPass()) {
        Compiler::Error(Compiler::MissingObjectContext, self);
      }
      valid = false;
    }
  }

  // invoke() will return Variant
  if (cls->isInterface() ||
      (func->isVirtual() &&
       (!Option::WholeProgram || func->isAbstract() ||
        (func->hasOverride() && cls->getAttribute(ClassScope::NotFinal))) &&
       !func->isPerfectVirtual())) {
    valid = false;
  }

  if (!valid) {
    setInvokeParams(ar);
    checkTypesImpl(ar, type, Type::Variant, coerce);
    m_valid = false; // so we use invoke() syntax
    if (!Option::AllDynamic) {
      func->setDynamic();
    }
    assert(m_actualType);
    return m_actualType;
  }

  assert(func);
  return checkParamsAndReturn(ar, type, coerce, func, false);
}