Arquivos
hhvm/hphp/compiler/expression/dynamic_function_call.cpp
T
mwilliams d39bf0bcfe Method names should not be coerced to string
Zend fatals if the type is not string, where hphp would
coerce to string. In RepoAuthoritative mode, this meant that
scalar expressions would be converted to strings at bytecode
emission time, bypassing the fatal (or, in most cases, resulting
in a different fatal).
2013-04-18 12:19:35 -07:00

141 linhas
4.7 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#include <compiler/expression/dynamic_function_call.h>
#include <compiler/analysis/code_error.h>
#include <compiler/expression/expression_list.h>
#include <compiler/expression/scalar_expression.h>
#include <compiler/expression/simple_function_call.h>
#include <compiler/analysis/function_scope.h>
#include <compiler/analysis/class_scope.h>
#include <util/util.h>
#include <compiler/option.h>
#include <compiler/analysis/variable_table.h>
using namespace HPHP;
///////////////////////////////////////////////////////////////////////////////
// constructors/destructors
DynamicFunctionCall::DynamicFunctionCall
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
ExpressionPtr name, ExpressionListPtr params, ExpressionPtr cls)
: FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(DynamicFunctionCall),
name, "", params, cls) {
}
ExpressionPtr DynamicFunctionCall::clone() {
DynamicFunctionCallPtr exp(new DynamicFunctionCall(*this));
FunctionCall::deepCopy(exp);
return exp;
}
///////////////////////////////////////////////////////////////////////////////
// parser functions
///////////////////////////////////////////////////////////////////////////////
// static analysis functions
void DynamicFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
FunctionCall::analyzeProgram(ar);
if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
if (!m_className.empty()) {
resolveClass();
}
if (!m_class) {
addUserClass(ar, m_className);
}
if (m_params) {
m_params->markParams(canInvokeFewArgs());
}
if (!m_class && m_className.empty()) {
FunctionScopePtr fs = getFunctionScope();
VariableTablePtr vt = fs->getVariables();
vt->setAttribute(VariableTable::ContainsDynamicFunctionCall);
}
}
}
ExpressionPtr DynamicFunctionCall::preOptimize(AnalysisResultConstPtr ar) {
if (ExpressionPtr rep = FunctionCall::preOptimize(ar)) return rep;
if (m_nameExp->isScalar()) {
Variant v;
if (m_nameExp->getScalarValue(v) &&
v.isString()) {
string name = v.toString().c_str();
ExpressionPtr cls = m_class;
if (!cls && !m_className.empty()) {
cls = makeScalarExpression(ar, m_className);
}
return ExpressionPtr(NewSimpleFunctionCall(
getScope(), getLocation(),
name, m_params, cls));
}
}
return ExpressionPtr();
}
TypePtr DynamicFunctionCall::inferTypes(AnalysisResultPtr ar, TypePtr type,
bool coerce) {
reset();
ConstructPtr self = shared_from_this();
if (m_class) {
m_class->inferAndCheck(ar, Type::Any, false);
} else if (!m_className.empty()) {
ClassScopePtr cls = resolveClassWithChecks();
if (cls) {
m_classScope = cls;
}
}
m_nameExp->inferAndCheck(ar, Type::Some, false);
if (m_params) {
for (int i = 0; i < m_params->getCount(); i++) {
(*m_params)[i]->inferAndCheck(ar, Type::Variant, true);
}
}
return Type::Variant;
}
///////////////////////////////////////////////////////////////////////////////
// code generation functions
void DynamicFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
if (m_class || !m_className.empty()) {
StaticClassName::outputPHP(cg, ar);
cg_printf("::");
m_nameExp->outputPHP(cg, ar);
} else {
const char *prefix = Option::IdPrefix.c_str();
if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
cg.usingStream(CodeGenerator::PrimaryStream) &&
!m_nameExp->is(Expression::KindOfScalarExpression)) {
cg_printf("${%sdynamic_load($%stmp = (", prefix, prefix);
m_nameExp->outputPHP(cg, ar);
cg_printf("), '%stmp'", prefix);
cg_printf(")}");
} else {
m_nameExp->outputPHP(cg, ar);
}
}
cg_printf("(");
if (m_params) m_params->outputPHP(cg, ar);
cg_printf(")");
}