/src/compiler/expression/simple_function_call.cpp
C++ | 1408 lines | 1211 code | 95 blank | 102 comment | 443 complexity | b3d1b7cac8b20532472e2169f47aefe8 MD5 | raw file
- /*
- +----------------------------------------------------------------------+
- | 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/simple_function_call.h>
- #include <compiler/analysis/file_scope.h>
- #include <compiler/analysis/function_scope.h>
- #include <compiler/analysis/class_scope.h>
- #include <compiler/analysis/code_error.h>
- #include <compiler/expression/expression_list.h>
- #include <compiler/expression/scalar_expression.h>
- #include <compiler/expression/constant_expression.h>
- #include <compiler/expression/assignment_expression.h>
- #include <compiler/expression/array_pair_expression.h>
- #include <compiler/expression/array_element_expression.h>
- #include <compiler/expression/unary_op_expression.h>
- #include <compiler/expression/parameter_expression.h>
- #include <compiler/statement/method_statement.h>
- #include <compiler/analysis/constant_table.h>
- #include <compiler/analysis/variable_table.h>
- #include <util/util.h>
- #include <compiler/option.h>
- #include <compiler/expression/simple_variable.h>
- #include <compiler/parser/parser.h>
- #include <runtime/base/complex_types.h>
- #include <runtime/base/externals.h>
- #include <runtime/base/execution_context.h>
- #include <runtime/base/array/array_init.h>
- #include <runtime/base/string_util.h>
- #include <runtime/ext/ext_variable.h>
- using namespace HPHP;
- using namespace std;
- using namespace boost;
- ///////////////////////////////////////////////////////////////////////////////
- // statics
- std::map<std::string, int> SimpleFunctionCall::FunctionTypeMap;
- void SimpleFunctionCall::InitFunctionTypeMap() {
- if (FunctionTypeMap.empty()) {
- FunctionTypeMap["define"] = DefineFunction;
- FunctionTypeMap["create_function"] = CreateFunction;
- FunctionTypeMap["func_get_arg"] = VariableArgumentFunction;
- FunctionTypeMap["func_get_args"] = VariableArgumentFunction;
- FunctionTypeMap["func_num_args"] = VariableArgumentFunction;
- FunctionTypeMap["extract"] = ExtractFunction;
- FunctionTypeMap["compact"] = CompactFunction;
- FunctionTypeMap["shell_exec"] = ShellExecFunction;
- FunctionTypeMap["exec"] = ShellExecFunction;
- FunctionTypeMap["passthru"] = ShellExecFunction;
- FunctionTypeMap["system"] = ShellExecFunction;
- FunctionTypeMap["defined"] = DefinedFunction;
- FunctionTypeMap["function_exists"] = FunctionExistsFunction;
- FunctionTypeMap["class_exists"] = ClassExistsFunction;
- FunctionTypeMap["interface_exists"] = InterfaceExistsFunction;
- FunctionTypeMap["constant"] = ConstantFunction;
- FunctionTypeMap["unserialize"] = UnserializeFunction;
- FunctionTypeMap["apc_fetch"] = UnserializeFunction;
- FunctionTypeMap["get_defined_vars"] = GetDefinedVarsFunction;
- FunctionTypeMap["fb_call_user_func_safe"] = FBCallUserFuncSafeFunction;
- FunctionTypeMap["fb_call_user_func_array_safe"] =
- FBCallUserFuncSafeFunction;
- FunctionTypeMap["fb_call_user_func_safe_return"] =
- FBCallUserFuncSafeFunction;
- }
- }
- static class FunctionTypeMapInitializer {
- public:
- FunctionTypeMapInitializer() {
- SimpleFunctionCall::InitFunctionTypeMap();
- }
- } s_function_type_map_initializer;
- ///////////////////////////////////////////////////////////////////////////////
- // constructors/destructors
- SimpleFunctionCall::SimpleFunctionCall
- (EXPRESSION_CONSTRUCTOR_PARAMETERS,
- const std::string &name, ExpressionListPtr params, ExpressionPtr cls)
- : FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(SimpleFunctionCall),
- ExpressionPtr(), name, params, cls),
- m_type(UnknownType), m_dynamicConstant(false),
- m_builtinFunction(false), m_noPrefix(false), m_dynamicInvoke(false),
- m_safe(0), m_extra(NULL) {
- if (Option::ParseTimeOpts && !m_class && m_className.empty()) {
- m_dynamicInvoke = Option::DynamicInvokeFunctions.find(m_name) !=
- Option::DynamicInvokeFunctions.end();
- map<string, int>::const_iterator iter =
- FunctionTypeMap.find(m_name);
- if (iter != FunctionTypeMap.end()) {
- m_type = iter->second;
- }
- }
- }
- ExpressionPtr SimpleFunctionCall::clone() {
- SimpleFunctionCallPtr exp(new SimpleFunctionCall(*this));
- deepCopy(exp);
- return exp;
- }
- void SimpleFunctionCall::deepCopy(SimpleFunctionCallPtr exp) {
- FunctionCall::deepCopy(exp);
- exp->m_safeDef = Clone(m_safeDef);
- }
- ///////////////////////////////////////////////////////////////////////////////
- // parser functions
- void SimpleFunctionCall::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) {
- if (m_class) return;
- ConstructPtr self = shared_from_this();
- if (m_className.empty()) {
- switch (m_type) {
- case DefineFunction:
- if (m_params && unsigned(m_params->getCount() - 2) <= 1u) {
- // need to register the constant before AnalyzeAll, so that
- // DefinedFunction can mark this volatile
- ExpressionPtr ename = (*m_params)[0];
- if (ConstantExpressionPtr cname =
- dynamic_pointer_cast<ConstantExpression>(ename)) {
- /*
- Hack: If the name of the constant being defined is itself
- a constant expression, assume that its not yet defined.
- So define(FOO, 'bar') is equivalent to define('FOO', 'bar').
- */
- ename = makeScalarExpression(ar, cname->getName());
- m_params->removeElement(0);
- m_params->insertElement(ename);
- }
- ScalarExpressionPtr name =
- dynamic_pointer_cast<ScalarExpression>(ename);
- if (name) {
- string varName = name->getIdentifier();
- if (varName.empty()) break;
- AnalysisResult::Locker lock(ar);
- fs->declareConstant(lock.get(), varName);
- // handling define("CONSTANT", ...);
- ExpressionPtr value = (*m_params)[1];
- BlockScopePtr block = lock->findConstantDeclarer(varName);
- ConstantTablePtr constants = block->getConstants();
- if (constants != ar->getConstants()) {
- constants->add(varName, Type::Some, value, ar, self);
- }
- }
- }
- break;
- case CreateFunction:
- if (m_params->getCount() == 2 &&
- (*m_params)[0]->isLiteralString() &&
- (*m_params)[1]->isLiteralString()) {
- string params = (*m_params)[0]->getLiteralString();
- string body = (*m_params)[1]->getLiteralString();
- m_lambda = CodeGenerator::GetNewLambda();
- string code = "function " + m_lambda + "(" + params + ") "
- "{" + body + "}";
- m_lambda = "1_" + m_lambda;
- ar->appendExtraCode(fs->getName(), code);
- }
- break;
- case VariableArgumentFunction:
- /*
- Note:
- At this point, we dont have a function scope, so we set
- the flags on the FileScope.
- The FileScope maintains a stack of attributes, so that
- it correctly handles each function.
- But note that later phases should set/get the attribute
- directly on the FunctionScope, rather than on the FileScope
- */
- fs->setAttribute(FileScope::VariableArgument);
- break;
- case ExtractFunction:
- fs->setAttribute(FileScope::ContainsLDynamicVariable);
- fs->setAttribute(FileScope::ContainsExtract);
- break;
- case CompactFunction: {
- // If all the parameters in the compact() call are statically known,
- // there is no need to create a variable table.
- vector<ExpressionPtr> literals;
- if (m_params->flattenLiteralStrings(literals)) {
- m_type = StaticCompactFunction;
- m_params->clearElements();
- for (unsigned i = 0; i < literals.size(); i++) {
- m_params->addElement(literals[i]);
- }
- } else {
- fs->setAttribute(FileScope::ContainsDynamicVariable);
- }
- fs->setAttribute(FileScope::ContainsCompact);
- break;
- }
- case GetDefinedVarsFunction:
- fs->setAttribute(FileScope::ContainsDynamicVariable);
- fs->setAttribute(FileScope::ContainsGetDefinedVars);
- fs->setAttribute(FileScope::ContainsCompact);
- break;
- default:
- break;
- }
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // static analysis functions
- void SimpleFunctionCall::addDependencies(AnalysisResultPtr ar) {
- if (!m_class) {
- if (m_className.empty()) {
- addUserFunction(ar, m_name);
- } else if ((!isParent() && !isSelf()) ||
- getOriginalScope() != getScope()) {
- addUserClass(ar, m_className);
- }
- }
- }
- void SimpleFunctionCall::setupScopes(AnalysisResultConstPtr ar) {
- FunctionScopePtr func;
- if (!m_class && m_className.empty()) {
- if (!m_dynamicInvoke) {
- bool namespaced = (m_name[0] == '\\');
- if (namespaced) {
- m_name = m_name.substr(1);
- }
- func = ar->findFunction(m_name);
- if (!func && namespaced) {
- int pos = m_name.rfind('\\');
- m_name = m_name.substr(pos + 1);
- func = ar->findFunction(m_name);
- }
- }
- } else {
- ClassScopePtr cls = resolveClass();
- if (cls) {
- m_classScope = cls;
- if (m_name == "__construct") {
- func = cls->findConstructor(ar, true);
- } else {
- func = cls->findFunction(ar, m_name, true, true);
- }
- }
- }
- if (func && !func->isRedeclaring()) {
- if (m_funcScope != func) {
- m_funcScope = func;
- ASSERT(ar->getPhase() != AnalysisResult::FirstInference);
- Construct::recomputeEffects();
- m_funcScope->addCaller(getScope());
- }
- }
- }
- void SimpleFunctionCall::addLateDependencies(AnalysisResultConstPtr ar) {
- m_funcScope.reset();
- m_classScope.reset();
- setupScopes(ar);
- }
- ConstructPtr SimpleFunctionCall::getNthKid(int n) const {
- if (n == 1) return m_safeDef;
- return FunctionCall::getNthKid(n);
- }
- void SimpleFunctionCall::setNthKid(int n, ConstructPtr cp) {
- if (n == 1) {
- m_safeDef = boost::dynamic_pointer_cast<Expression>(cp);
- } else {
- FunctionCall::setNthKid(n, cp);
- }
- }
- void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
- FunctionCall::analyzeProgram(ar);
- if (m_class) {
- if (!Option::AllDynamic) {
- setDynamicByIdentifier(ar, m_name);
- }
- } else if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
- addDependencies(ar);
- }
- if (m_safeDef) m_safeDef->analyzeProgram(ar);
- if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
- ConstructPtr self = shared_from_this();
- // Look up the corresponding FunctionScope and ClassScope
- // for this function call
- setupScopes(ar);
- if (m_funcScope && m_funcScope->getOptFunction()) {
- SimpleFunctionCallPtr self(
- static_pointer_cast<SimpleFunctionCall>(shared_from_this()));
- (m_funcScope->getOptFunction())(0, ar, self, 1);
- }
- // check for dynamic constant and volatile function/class
- if (!m_class && m_className.empty() &&
- (m_type == DefinedFunction ||
- m_type == FunctionExistsFunction ||
- m_type == FBCallUserFuncSafeFunction ||
- m_type == ClassExistsFunction ||
- m_type == InterfaceExistsFunction) &&
- 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()) {
- string symbol = name->getLiteralString();
- switch (m_type) {
- case DefinedFunction: {
- ConstantTablePtr constants = ar->getConstants();
- if (!constants->isPresent(symbol)) {
- // user constant
- BlockScopePtr block = ar->findConstantDeclarer(symbol);
- if (block) { // found the constant
- constants = block->getConstants();
- // set to be dynamic
- if (m_type == DefinedFunction) {
- constants->setDynamic(ar, symbol);
- }
- }
- }
- break;
- }
- case FBCallUserFuncSafeFunction:
- case FunctionExistsFunction: {
- FunctionScopePtr func = ar->findFunction(Util::toLower(symbol));
- if (func && func->isUserFunction()) {
- func->setVolatile();
- }
- break;
- }
- case InterfaceExistsFunction:
- case ClassExistsFunction: {
- ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
- if (cls && cls->isUserClass()) {
- cls->setVolatile();
- }
- break;
- }
- default:
- ASSERT(false);
- }
- }
- } else if ((m_type == InterfaceExistsFunction ||
- m_type == ClassExistsFunction) &&
- value->is(KindOfSimpleVariable)) {
- SimpleVariablePtr name = dynamic_pointer_cast<SimpleVariable>(value);
- if (name && name->getSymbol()) {
- // name is checked as class name
- name->getSymbol()->setClassName();
- }
- }
- }
- if (m_type == StaticCompactFunction) {
- FunctionScopePtr fs = getFunctionScope();
- VariableTablePtr vt = fs->getVariables();
- if (vt->isPseudoMainTable() ||
- vt->getAttribute(VariableTable::ContainsDynamicVariable)) {
- // When there is a variable table already, we will keep the ordinary
- // compact() call.
- m_type = CompactFunction;
- } else {
- // compact('a', 'b', 'c') becomes compact('a', $a, 'b', $b, 'c', $c)
- vector<ExpressionPtr> new_params;
- vector<string> strs;
- for (int i = 0; i < m_params->getCount(); i++) {
- ExpressionPtr e = (*m_params)[i];
- assert(e->isLiteralString());
- string name = e->getLiteralString();
- // no need to record duplicate names
- bool found = false;
- for (unsigned j = 0; j < strs.size(); j++) {
- if (strcasecmp(name.data(), strs[j].data()) == 0) {
- found = true;
- break;
- }
- }
- if (found) continue;
- strs.push_back(name);
- SimpleVariablePtr var(new SimpleVariable(
- e->getScope(), e->getLocation(), name));
- var->copyContext(e);
- var->updateSymbol(SimpleVariablePtr());
- new_params.push_back(e);
- new_params.push_back(var);
- }
- m_params->clearElements();
- for (unsigned i = 0; i < new_params.size(); i++) {
- m_params->addElement(new_params[i]);
- }
- }
- }
- if (m_type == UnserializeFunction) {
- ar->forceClassVariants(getOriginalClass(), false);
- }
- if (m_params) {
- markRefParams(m_funcScope, m_name, canInvokeFewArgs());
- }
- } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
- if (!m_class && !m_redeclared && !m_dynamicInvoke && !m_funcScope &&
- (m_className.empty() ||
- (m_classScope &&
- !m_classScope->isTrait() &&
- !m_classScope->derivesFromRedeclaring() &&
- !m_classScope->getAttribute(
- ClassScope::HasUnknownStaticMethodHandler) &&
- !m_classScope->getAttribute(
- ClassScope::InheritsUnknownStaticMethodHandler)))) {
- Compiler::Error(Compiler::UnknownFunction, shared_from_this());
- }
- }
- }
- bool SimpleFunctionCall::readsLocals() const {
- return m_type == GetDefinedVarsFunction ||
- m_type == CompactFunction;
- }
- bool SimpleFunctionCall::writesLocals() const {
- return m_type == ExtractFunction;
- }
- void SimpleFunctionCall::updateVtFlags() {
- FunctionScopeRawPtr f = getFunctionScope();
- if (f) {
- if (m_funcScope) {
- if (m_funcScope->getContextSensitive()) {
- f->setInlineSameContext(true);
- }
- if ((m_classScope && (isSelf() || isParent()) &&
- m_funcScope->usesLSB()) ||
- isStatic() ||
- m_type == FBCallUserFuncSafeFunction ||
- m_name == "call_user_func" ||
- m_name == "call_user_func_array" ||
- m_name == "forward_static_call" ||
- m_name == "forward_static_call_array" ||
- m_name == "hphp_create_continuation" ||
- m_name == "get_called_class") {
- f->setNextLSB(true);
- }
- }
- }
- if (m_type != UnknownType) {
- VariableTablePtr vt = getScope()->getVariables();
- switch (m_type) {
- case ExtractFunction:
- vt->setAttribute(VariableTable::ContainsLDynamicVariable);
- vt->setAttribute(VariableTable::ContainsExtract);
- break;
- case CompactFunction:
- vt->setAttribute(VariableTable::ContainsDynamicVariable);
- case StaticCompactFunction:
- vt->setAttribute(VariableTable::ContainsCompact);
- break;
- case GetDefinedVarsFunction:
- vt->setAttribute(VariableTable::ContainsDynamicVariable);
- vt->setAttribute(VariableTable::ContainsGetDefinedVars);
- vt->setAttribute(VariableTable::ContainsCompact);
- break;
- }
- }
- }
- bool SimpleFunctionCall::isDefineWithoutImpl(AnalysisResultConstPtr ar) {
- if (m_class || !m_className.empty()) return false;
- if (m_type == DefineFunction && m_params &&
- unsigned(m_params->getCount() - 2) <= 1u) {
- if (m_dynamicConstant) return false;
- ScalarExpressionPtr name =
- dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
- if (!name) return false;
- string varName = name->getIdentifier();
- if (varName.empty()) return false;
- if (ar->isSystemConstant(varName)) {
- assert(!m_extra);
- return true;
- }
- ExpressionPtr value = (*m_params)[1];
- if (ar->isConstantRedeclared(varName)) {
- return false;
- }
- Variant scalarValue;
- return (value->isScalar() &&
- value->getScalarValue(scalarValue) &&
- scalarValue.isAllowedAsConstantValue());
- } else {
- return false;
- }
- }
- ExpressionPtr SimpleFunctionCall::optimize(AnalysisResultConstPtr ar) {
- if (m_class || !m_funcScope ||
- (!m_className.empty() && (!m_classScope || !isPresent()))) {
- return ExpressionPtr();
- }
- if (!m_funcScope->isUserFunction()) {
- if (m_type == ExtractFunction && m_params && m_params->getCount() >= 1) {
- ExpressionPtr vars = (*m_params)[0];
- while (vars) {
- if (vars->is(KindOfUnaryOpExpression) &&
- static_pointer_cast<UnaryOpExpression>(vars)->getOp() == T_ARRAY) {
- break;
- }
- if (vars->is(KindOfExpressionList)) {
- vars = static_pointer_cast<ExpressionList>(vars)->listValue();
- } else {
- vars = vars->getCanonPtr();
- }
- }
- if (vars) {
- bool svar = vars->isScalar();
- if (!svar && getScope()->getUpdated()) {
- /*
- * kind of a hack. If the extract param is non-scalar,
- * and we've made changes already, dont try to optimize yet.
- * this gives us a better chance of getting a scalar result.
- * Later, we should add more array optimizations, which would
- * allow us to optimize the generated code once the scalar
- * expressions are resolved
- */
- return ExpressionPtr();
- }
- int n = m_params->getCount();
- String prefix;
- int mode = EXTR_OVERWRITE;
- if (n >= 2) {
- Variant v;
- ExpressionPtr m = (*m_params)[1];
- if (m->isScalar() && m->getScalarValue(v)) {
- mode = v.toInt64();
- }
- if (n >= 3) {
- ExpressionPtr p = (*m_params)[2];
- if (p->isScalar() && p->getScalarValue(v)) {
- prefix = v.toString();
- }
- }
- }
- bool ref = mode & EXTR_REFS;
- mode &= ~EXTR_REFS;
- switch (mode) {
- case EXTR_PREFIX_ALL:
- case EXTR_PREFIX_INVALID:
- case EXTR_OVERWRITE: {
- ExpressionListPtr arr(
- static_pointer_cast<ExpressionList>(
- static_pointer_cast<UnaryOpExpression>(vars)->getExpression()));
- ExpressionListPtr rep(
- new ExpressionList(getScope(), getLocation(),
- ExpressionList::ListKindWrapped));
- string root_name;
- int n = arr ? arr->getCount() : 0;
- int i, j, k;
- for (i = j = k = 0; i < n; i++) {
- ArrayPairExpressionPtr ap(
- dynamic_pointer_cast<ArrayPairExpression>((*arr)[i]));
- assert(ap);
- String name;
- Variant voff;
- if (!ap->getName()) {
- voff = j++;
- } else {
- if (!ap->getName()->isScalar() ||
- !ap->getName()->getScalarValue(voff)) {
- return ExpressionPtr();
- }
- }
- name = voff.toString();
- if (mode == EXTR_PREFIX_ALL ||
- (mode == EXTR_PREFIX_INVALID &&
- !name.isValidVariableName())) {
- name = prefix + "_" + name;
- }
- if (!name.isValidVariableName()) continue;
- SimpleVariablePtr var(
- new SimpleVariable(getScope(), getLocation(), name.data()));
- var->updateSymbol(SimpleVariablePtr());
- ExpressionPtr val(ap->getValue());
- if (!val->isScalar()) {
- if (root_name.empty()) {
- root_name = "t" + lexical_cast<string>(
- getFunctionScope()->nextInlineIndex());
- SimpleVariablePtr rv(
- new SimpleVariable(getScope(), getLocation(), root_name));
- rv->updateSymbol(SimpleVariablePtr());
- rv->getSymbol()->setHidden();
- ExpressionPtr root(
- new AssignmentExpression(getScope(), getLocation(),
- rv, (*m_params)[0], false));
- rep->insertElement(root);
- }
- SimpleVariablePtr rv(
- new SimpleVariable(getScope(), getLocation(), root_name));
- rv->updateSymbol(SimpleVariablePtr());
- rv->getSymbol()->setHidden();
- ExpressionPtr offset(makeScalarExpression(ar, voff));
- val = ExpressionPtr(
- new ArrayElementExpression(getScope(), getLocation(),
- rv, offset));
- }
- ExpressionPtr a(
- new AssignmentExpression(getScope(), getLocation(),
- var, val, ref));
- rep->addElement(a);
- k++;
- }
- if (root_name.empty()) {
- if ((*m_params)[0]->hasEffect()) {
- rep->insertElement((*m_params)[0]);
- }
- } else {
- ExpressionListPtr unset_list
- (new ExpressionList(getScope(), getLocation()));
- SimpleVariablePtr rv(
- new SimpleVariable(getScope(), getLocation(), root_name));
- rv->updateSymbol(SimpleVariablePtr());
- unset_list->addElement(rv);
- ExpressionPtr unset(
- new UnaryOpExpression(getScope(), getLocation(),
- unset_list, T_UNSET, true));
- rep->addElement(unset);
- }
- rep->addElement(makeScalarExpression(ar, k));
- return replaceValue(rep);
- }
- default: break;
- }
- }
- }
- }
- if (!m_classScope && !m_funcScope->isUserFunction()) {
- if (m_type == UnknownType && m_funcScope->isFoldable()) {
- Array arr;
- if (m_params) {
- if (!m_params->isScalar()) return ExpressionPtr();
- for (int i = 0, n = m_params->getCount(); i < n; ++i) {
- Variant v;
- if (!(*m_params)[i]->getScalarValue(v)) return ExpressionPtr();
- arr.set(i, v);
- }
- if (m_arrayParams) {
- arr = arr[0];
- }
- }
- try {
- g_context->setThrowAllErrors(true);
- Variant v = invoke_builtin(m_funcScope->getName().c_str(),
- arr, -1, true);
- g_context->setThrowAllErrors(false);
- return makeScalarExpression(ar, v);
- } catch (...) {
- g_context->setThrowAllErrors(false);
- }
- return ExpressionPtr();
- }
- if (m_funcScope->getOptFunction()) {
- SimpleFunctionCallPtr self(
- static_pointer_cast<SimpleFunctionCall>(shared_from_this()));
- ExpressionPtr e = (m_funcScope->getOptFunction())(0, ar, self, 0);
- if (e) return e;
- }
- }
- if (m_type != UnknownType || m_safe) {
- return ExpressionPtr();
- }
- return inliner(ar, ExpressionPtr(), m_localThis);
- }
- ExpressionPtr SimpleFunctionCall::preOptimize(AnalysisResultConstPtr ar) {
- if (m_class) updateClassName();
- if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
- return ExpressionPtr();
- }
- if (ExpressionPtr rep = onPreOptimize(ar)) {
- return rep;
- }
- if (ExpressionPtr rep = optimize(ar)) {
- return rep;
- }
- if (!m_class && m_className.empty() &&
- (m_type == DefineFunction ||
- m_type == DefinedFunction ||
- m_type == FBCallUserFuncSafeFunction ||
- m_type == FunctionExistsFunction ||
- m_type == ClassExistsFunction ||
- m_type == InterfaceExistsFunction) &&
- m_params &&
- (m_type == DefineFunction ?
- unsigned(m_params->getCount() - 2) <= 1u :
- m_type == FBCallUserFuncSafeFunction ? m_params->getCount() >= 1 :
- m_params->getCount() == 1)) {
- ExpressionPtr value = (*m_params)[0];
- if (value->isScalar()) {
- ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value);
- if (name && name->isLiteralString()) {
- string symbol = name->getLiteralString();
- switch (m_type) {
- case DefineFunction: {
- ConstantTableConstPtr constants = ar->getConstants();
- // system constant
- if (constants->isPresent(symbol)) {
- break;
- }
- // user constant
- BlockScopeConstPtr block = ar->findConstantDeclarer(symbol);
- // not found (i.e., undefined)
- if (!block) break;
- constants = block->getConstants();
- const Symbol *sym = constants->getSymbol(symbol);
- assert(sym);
- m_extra = (void *)sym;
- Lock lock(BlockScope::s_constMutex);
- if (!sym->isDynamic() && sym->getValue() != (*m_params)[1]) {
- if (sym->getDeclaration() != shared_from_this()) {
- // redeclared
- const_cast<Symbol*>(sym)->setDynamic();
- }
- const_cast<Symbol*>(sym)->setValue((*m_params)[1]);
- getScope()->addUpdates(BlockScope::UseKindConstRef);
- }
- break;
- }
- case DefinedFunction: {
- if (symbol == "false" ||
- symbol == "true" ||
- symbol == "null") {
- return CONSTANT("true");
- }
- ConstantTableConstPtr constants = ar->getConstants();
- // system constant
- if (constants->isPresent(symbol) && !constants->isDynamic(symbol)) {
- return CONSTANT("true");
- }
- // user constant
- BlockScopeConstPtr block = ar->findConstantDeclarer(symbol);
- // not found (i.e., undefined)
- if (!block) {
- if (symbol.find("::") == std::string::npos) {
- return CONSTANT("false");
- } else {
- // e.g., defined("self::ZERO")
- return ExpressionPtr();
- }
- }
- constants = block->getConstants();
- // already set to be dynamic
- if (constants->isDynamic(symbol)) return ExpressionPtr();
- Lock lock(BlockScope::s_constMutex);
- ConstructPtr decl = constants->getValue(symbol);
- ExpressionPtr constValue = dynamic_pointer_cast<Expression>(decl);
- if (constValue->isScalar()) {
- return CONSTANT("true");
- } else {
- return ExpressionPtr();
- }
- break;
- }
- case FBCallUserFuncSafeFunction:
- case FunctionExistsFunction: {
- const std::string &lname = Util::toLower(symbol);
- if (Option::DynamicInvokeFunctions.find(lname) ==
- Option::DynamicInvokeFunctions.end()) {
- FunctionScopePtr func = ar->findFunction(lname);
- if (!func && m_type == FunctionExistsFunction) {
- return CONSTANT("false");
- }
- if (func->isUserFunction()) {
- func->setVolatile();
- }
- if (!func->isVolatile() && m_type == FunctionExistsFunction) {
- return CONSTANT("true");
- }
- }
- break;
- }
- case InterfaceExistsFunction: {
- ClassScopePtrVec classes = ar->findClasses(Util::toLower(symbol));
- bool interfaceFound = false;
- for (ClassScopePtrVec::const_iterator it = classes.begin();
- it != classes.end(); ++it) {
- ClassScopePtr cls = *it;
- if (cls->isUserClass()) cls->setVolatile();
- if (cls->isInterface()) {
- interfaceFound = true;
- }
- }
- if (!interfaceFound) return CONSTANT("false");
- if (classes.size() == 1 && !classes.back()->isVolatile()) {
- return CONSTANT("true");
- }
- break;
- }
- case ClassExistsFunction: {
- ClassScopePtrVec classes = ar->findClasses(Util::toLower(symbol));
- bool classFound = false;
- for (ClassScopePtrVec::const_iterator it = classes.begin();
- it != classes.end(); ++it) {
- ClassScopePtr cls = *it;
- if (cls->isUserClass()) cls->setVolatile();
- if (!cls->isInterface()) {
- classFound = true;
- }
- }
- if (!classFound) return CONSTANT("false");
- if (classes.size() == 1 && !classes.back()->isVolatile()) {
- return CONSTANT("true");
- }
- break;
- }
- default:
- ASSERT(false);
- }
- }
- }
- }
- return ExpressionPtr();
- }
- ExpressionPtr SimpleFunctionCall::postOptimize(AnalysisResultConstPtr ar) {
- if (!Option::KeepStatementsWithNoEffect && isDefineWithoutImpl(ar)) {
- Construct::recomputeEffects();
- if (m_extra) {
- Symbol *sym = (Symbol *)m_extra;
- Lock lock(BlockScope::s_constMutex);
- sym->setReplaced();
- }
- return m_extra ? CONSTANT("true") : CONSTANT("false");
- }
- if (m_type == StaticCompactFunction) {
- for (int i = 0; i < m_params->getCount(); i += 2) {
- ExpressionPtr e = (*m_params)[i + 1];
- if (e->is(KindOfUnaryOpExpression) &&
- static_pointer_cast<UnaryOpExpression>(e)->getOp() == T_UNSET_CAST) {
- m_params->removeElement(i);
- m_params->removeElement(i);
- i -= 2;
- m_extraArg -= 2;
- if (m_extraArg < 0) m_extraArg = 0;
- }
- }
- if (!m_params->getCount()) {
- ExpressionPtr rep(new UnaryOpExpression(getScope(), getLocation(),
- ExpressionPtr(), T_ARRAY, true));
- return replaceValue(rep);
- }
- m_params->resetOutputCount();
- }
- /*
- Dont do this for now. Need to take account of newly created
- variables etc (which would normally be handled by inferTypes).
- if (ExpressionPtr rep = optimize(ar)) {
- return rep;
- }
- */
- return FunctionCall::postOptimize(ar);
- }
- int SimpleFunctionCall::getLocalEffects() const {
- if (m_class) return UnknownEffect;
- if (m_funcScope && !m_funcScope->hasEffect()) {
- return 0;
- }
- return UnknownEffect;
- }
- TypePtr SimpleFunctionCall::inferTypes(AnalysisResultPtr ar, TypePtr type,
- bool coerce) {
- ASSERT(false);
- return TypePtr();
- }
- TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
- bool coerce) {
- ASSERT(type);
- IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
- resetTypes();
- reset();
- if (m_class) {
- m_class->inferAndCheck(ar, Type::Any, false);
- }
- if (m_safeDef) {
- m_safeDef->inferAndCheck(ar, Type::Any, false);
- }
- if (m_safe) {
- getScope()->getVariables()->
- setAttribute(VariableTable::NeedGlobalPointer);
- }
- ConstructPtr self = shared_from_this();
- // handling define("CONSTANT", ...);
- if (!m_class && m_className.empty()) {
- if (m_type == DefineFunction && m_params &&
- unsigned(m_params->getCount() - 2) <= 1u) {
- ScalarExpressionPtr name =
- dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
- if (name) {
- string varName = name->getIdentifier();
- if (!varName.empty()) {
- ExpressionPtr value = (*m_params)[1];
- TypePtr varType = value->inferAndCheck(ar, Type::Some, false);
- BlockScopePtr block;
- bool newlyDeclared = false;
- {
- Lock lock(ar->getMutex());
- block = ar->findConstantDeclarer(varName);
- if (!block) {
- FileScopeRawPtr fs(getFileScope());
- GET_LOCK(fs); // file scope cannot depend on a function scope
- fs->declareConstant(ar, varName);
- block = ar->findConstantDeclarer(varName);
- newlyDeclared = true;
- }
- }
- ASSERT(block);
- ConstantTablePtr constants = block->getConstants();
- if (constants != ar->getConstants()) {
- TRY_LOCK(block);
- if (value && !value->isScalar()) {
- constants->setDynamic(ar, varName);
- varType = Type::Variant;
- }
- if (constants->isDynamic(varName)) {
- m_dynamicConstant = true;
- getScope()->getVariables()->
- setAttribute(VariableTable::NeedGlobalPointer);
- } else {
- if (newlyDeclared) {
- const Symbol *sym = constants->getSymbol(varName);
- ASSERT(!sym || !sym->declarationSet());
- constants->add(varName, varType, value, ar, self);
- sym = constants->getSymbol(varName);
- assert(sym);
- m_extra = (void *)sym;
- } else {
- constants->setType(ar, varName, varType, true);
- }
- }
- // in case the old 'value' has been optimized
- constants->setValue(ar, varName, value);
- } else {
- assert(!newlyDeclared);
- }
- m_valid = true;
- return checkTypesImpl(ar, type, Type::Boolean, coerce);
- }
- }
- if (getScope()->isFirstPass()) {
- Compiler::Error(Compiler::BadDefine, self);
- }
- } else if (m_type == ExtractFunction || m_type == GetDefinedVarsFunction) {
- getScope()->getVariables()->forceVariants(ar, VariableTable::AnyVars);
- }
- }
- FunctionScopePtr func;
- if (!m_class && m_className.empty()) {
- if (!m_dynamicInvoke) {
- func = ar->findFunction(m_name);
- }
- } else {
- ClassScopePtr cls = resolveClass();
- if (cls && !isPresent()) {
- getScope()->getVariables()
- ->setAttribute(VariableTable::NeedGlobalPointer);
- }
- if (!cls) {
- if (!m_class && !isRedeclared() && getScope()->isFirstPass()) {
- Compiler::Error(Compiler::UnknownClass, self);
- }
- if (m_params) {
- m_params->inferAndCheck(ar, Type::Some, false);
- m_params->markParams(canInvokeFewArgs());
- }
- return checkTypesImpl(ar, type, Type::Variant, coerce);
- }
- m_classScope = cls;
- 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 = getOriginalClass();
- FunctionScopePtr funcThis = getOriginalFunction();
- if (!Option::AllDynamic &&
- (!clsThis ||
- (clsThis != m_classScope &&
- !clsThis->derivesFrom(ar, m_className, true, false)) ||
- funcThis->isStatic())) {
- func->setDynamic();
- }
- }
- }
- if (!func || func->isRedeclaring() || func->isAbstract()) {
- if (m_funcScope) {
- m_funcScope.reset();
- Construct::recomputeEffects();
- }
- if (func && func->isRedeclaring()) {
- m_redeclared = true;
- getScope()->getVariables()->
- setAttribute(VariableTable::NeedGlobalPointer);
- }
- if (m_params) {
- if (func && func->isRedeclaring()) {
- FunctionScope::FunctionInfoPtr info =
- FunctionScope::GetFunctionInfo(m_name);
- assert(info);
- for (int i = m_params->getCount(); i--; ) {
- if (!Option::WholeProgram || info->isRefParam(i)) {
- m_params->markParam(i, canInvokeFewArgs());
- }
- }
- }
- if (m_arrayParams) {
- (*m_params)[0]->inferAndCheck(ar, Type::Array, false);
- } else {
- m_params->inferAndCheck(ar, Type::Some, false);
- }
- }
- return checkTypesImpl(ar, type, Type::Variant, coerce);
- } else if (func != m_funcScope) {
- ASSERT(!m_funcScope ||
- !func->hasUser(getScope(), BlockScope::UseKindCaller));
- m_funcScope = func;
- m_funcScope->addCaller(getScope(), !type->is(Type::KindOfAny));
- Construct::recomputeEffects();
- }
- m_builtinFunction = (!func->isUserFunction() || func->isSepExtension());
- beforeCheck(ar);
- m_valid = true;
- TypePtr rtype = checkParamsAndReturn(ar, type, coerce,
- func, m_arrayParams);
- // this is ok un-guarded b/c this value never gets un-set (once its
- // true its always true) and the value itself doesn't get read
- // until outputCPP time
- if (m_arrayParams && func && !m_builtinFunction) func->setDirectInvoke();
- if (m_safe) {
- TypePtr atype = getActualType();
- if (m_safe > 0 && !m_safeDef) {
- atype = Type::Array;
- } else if (!m_safeDef) {
- atype = Type::Variant;
- } else {
- TypePtr t = m_safeDef->getActualType();
- if (!t || !atype || !Type::SameType(t, atype)) {
- atype = Type::Variant;
- }
- }
- rtype = checkTypesImpl(ar, type, atype, coerce);
- m_voidReturn = m_voidWrapper = false;
- }
- if (m_valid && !m_className.empty() &&
- (!m_funcScope || !m_funcScope->isStatic())) {
- int objCall = checkObjCall(ar);
- if (objCall < 0 || (objCall > 0 && !m_localThis.empty())) {
- m_implementedType = Type::Variant;
- }
- }
- ASSERT(rtype);
- return rtype;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // code generation functions
- void SimpleFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
- outputLineMap(cg, ar);
- if (m_class || !m_className.empty()) {
- StaticClassName::outputPHP(cg, ar);
- cg_printf("::%s(", m_origName.c_str());
- } else {
- if (cg.getOutput() == CodeGenerator::InlinedPHP ||
- cg.getOutput() == CodeGenerator::TrimmedPHP) {
- if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
- cg.usingStream(CodeGenerator::PrimaryStream) &&
- Option::DynamicFunctionCalls.find(m_name) !=
- Option::DynamicFunctionCalls.end()) {
- int funcNamePos = Option::DynamicFunctionCalls[m_name];
- if (m_params && m_params->getCount() &&
- m_params->getCount() >= funcNamePos + 1) {
- if (funcNamePos == -1) funcNamePos = m_params->getCount() - 1;
- ExpressionPtr funcName = (*m_params)[funcNamePos];
- if (!funcName->is(Expression::KindOfScalarExpression)) {
- cg_printf("%s(", m_name.c_str());
- for (int i = 0; i < m_params->getCount(); i++) {
- if (i > 0) cg_printf(", ");
- if (i == funcNamePos) {
- cg_printf("%sdynamic_load(", Option::IdPrefix.c_str());
- funcName->outputPHP(cg, ar);
- cg_printf(")");
- } else {
- ExpressionPtr param = (*m_params)[i];
- if (param) param->outputPHP(cg, ar);
- }
- }
- cg_printf(")");
- return;
- }
- }
- }
- cg_printf("%s(", m_origName.c_str());
- } else {
- cg_printf("%s(", m_origName.c_str());
- }
- }
- if (m_params) m_params->outputPHP(cg, ar);
- cg_printf(")");
- }
- /*
- * returns: 1 - if the call is dynamic
- * -1 - if the call may be dynamic, depending on redeclared derivation
- * 0 - if the call is static (ie with an "empty" this).
- */
- static int isObjCall(AnalysisResultPtr ar,
- ClassScopeRawPtr thisCls, FunctionScopeRawPtr thisFunc,
- ClassScopeRawPtr methCls, const std::string &methClsName) {
- if (!thisCls || !thisFunc || thisFunc->isStatic()) return 0;
- if (thisCls == methCls) return 1;
- if (thisCls->derivesFrom(ar, methClsName, true, false)) return 1;
- if (thisCls->derivesFromRedeclaring() &&
- thisCls->derivesFrom(ar, methClsName, true, true)) {
- return -1;
- }
- return 0;
- }
- FunctionScopePtr
- SimpleFunctionCall::getFuncScopeFromParams(AnalysisResultPtr ar,
- BlockScopeRawPtr scope,
- ExpressionPtr clsName,
- ExpressionPtr funcName,
- ClassScopePtr &clsScope) {
- clsScope.reset();
- ScalarExpressionPtr clsName0(
- dynamic_pointer_cast<ScalarExpression>(clsName));
- ScalarExpressionPtr funcName0(
- dynamic_pointer_cast<ScalarExpression>(funcName));
- if (clsName0 && funcName0) {
- string cname = clsName0->getLiteralString();
- string fname = funcName0->getLiteralString();
- if (!fname.empty()) {
- if (!cname.empty()) {
- ClassScopePtr cscope(ar->findClass(cname));
- if (cscope && cscope->isRedeclaring()) {
- cscope = scope->findExactClass(Util::toLower(cname));
- }
- if (cscope) {
- FunctionScopePtr fscope(cscope->findFunction(ar, fname, true));
- if (fscope) {
- clsScope = cscope;
- }
- return fscope;
- }
- } else {
- FunctionScopePtr fscope(ar->findFunction(fname));
- return fscope;
- }
- }
- }
- return FunctionScopePtr();
- }
- int SimpleFunctionCall::checkObjCall(AnalysisResultPtr ar) {
- ClassScopeRawPtr orig = getOriginalClass();
- int objCall = isObjCall(ar, orig, getOriginalFunction(),
- m_classScope, m_className);
- if (objCall > 0 && m_localThis.empty() &&
- (getClassScope() != orig || getFunctionScope()->isStatic())) {
- int o = isObjCall(ar, getClassScope(), getFunctionScope(),
- orig, orig->getName());
- if (o <= 0) objCall = o;
- }
- return objCall;
- }
- bool SimpleFunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
- int state) {
- if (m_type == StaticCompactFunction) {
- if (!cg.inExpression()) return true;
- cg.wrapExpressionBegin();
- m_ciTemp = cg.createNewLocalId(shared_from_this());
- cg_printf("ArrayInit compact%d(%d);\n",
- m_ciTemp, m_params->getCount() / 2);
- for (int i = 0; i < m_params->getCount(); i += 2) {
- assert((*m_params)[i]->isLiteralString());
- string p = (*m_params)[i]->getLiteralString();
- ExpressionPtr e = (*m_params)[i + 1];
- if (e->is(KindOfSimpleVariable)
- && Type::SameType(e->getCPPType(), Type::Variant)) {
- SimpleVariablePtr sv = dynamic_pointer_cast<SimpleVariable>(e);
- const string &cppName = sv->getAssignableCPPVariable(ar);
- ASSERT(!cppName.empty());
- cg_printf("if (%s.isInitialized()) ", cppName.c_str());
- }
- e->preOutputCPP(cg, ar, 0);
- cg_printf("compact%d.add(", m_ciTemp);
- cg_printString(p, ar, shared_from_this());
- cg_printf(", ");
- e->outputCPP(cg, ar);
- cg_printf(");\n");
- }
- return true;
- }
- int objCall = 0;
- if (!m_className.empty() && (!m_funcScope || !m_funcScope->isStatic())) {
- objCall = checkObjCall(ar);
- if (objCall < 0) {
- /*
- We have X::foo (which is non-static) inside a non-static
- method of Y, where Y may or may not be derived from X, depending
- on redeclared classes.
- Revert to dynamic dispatch for this case.
- */
- m_valid = false;
- } else if (objCall > 0 && !m_localThis.empty()) {
- m_valid = false;
- }
- }
- if (m_valid) {
- bool ret = false;
- if (m_classScope &&
- (m_arrayParams || !m_funcScope->isStatic())) {
- ret = true;
- if (cg.inExpression()) {
- if (m_funcScope->isStatic()) {
- cg.wrapExpressionBegin();
- m_ciTemp = cg.createNewLocalId(shared_from_this());
- cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
- // mcp.isObj is by default false
- cg_printf("mcp%d.rootCls = %s%s::s_class_name.get();\n",
- m_ciTemp,
- Option::ClassPrefix, m_classScope->getId().c_str());
- } else {
- if (!objCall || m_arrayParams) {
- cg.wrapExpressionBegin();
- m_ciTemp = cg.createNewLocalId(shared_from_this());
- cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
- }
- if (objCall && m_arrayParams) {
- cg_printf("mcp%d.obj = %s;\n",
- m_ciTemp, getThisString(false).c_str());
- }
- }
- }
- } else if (m_arrayParams && !m_funcScope->isUserFunction()) {
- ret = true;
- if (cg.inExpression()) {
- cg.wrapExpressionBegin();
- cg_printf("extern Variant %s%s(void*,CArrRef);\n",
- Option::InvokePrefix, m_funcScope->getId().c_str());
- }
- }
- return FunctionCall::preOutputCPP(cg, ar, state) || ret;
- }
- // Short circuit out if inExpression() returns false
- if (!cg.inExpression()) return true;
- cg.wrapExpressionBegin();
- m_ciTemp = cg.createNewLocalId(shared_from_this());
- bool needHash = true;
- string escapedName(CodeGenerator::EscapeLabel(m_origName));
- string escapedClass;
- ClassScopePtr cls = m_classScope;
- if (!m_className.empty()) {
- if (!m_safe && !isPresent()) {
- ClassScope::OutputVolatileCheck(
- cg, ar, getScope(), m_origClassName, false);
- cg_printf(";\n");
- }
- escapedClass = CodeGenerator::EscapeLabel(m_className);
- }
- cg_printf("const CallInfo *cit%d = NULL;\n", m_ciTemp);
- if (!m_class && m_className.empty()) {
- cg_printf("void *vt%d = NULL;\n", m_ciTemp);
- } else {
- cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
- }
- bool safeCheck = false;
- if (m_safe) {
- if (!m_className.empty()) {
- if (!isPresent()) {
- cg_indentBegin("if (");
- ClassScope::OutputVolatileCheck(cg, ar, getScope(),
- m_origClassName, true);
- safeCheck = true;
- }
- } else if (!m_funcScope || m_funcScope->isVolatile()) {
- cg_indentBegin("if (");
- cg_printf("%s->FVF(%s)",
- cg.getGlobals(ar),
- CodeGenerator::FormatLabel(m_name).c_str());
- safeCheck = true;
- }
- }
- if (safeCheck) {
- cg_printf(") {\n");
- }
- if (!m_class && m_className.empty()) {
- if (m_redeclared && !m_dynamicInvoke) {
- needHash = false;
- cg_printf("cit%d = %s->GCI(%s);\n", m_ciTemp, cg.getGlobals(ar),
- CodeGenerator::FormatLabel(m_name).c_str());
- if (!safeCheck) {
- // If m_safe, check cit later, if null then yield null or safeDef
- cg_printf("if (!cit%d) invoke_failed(\"%s\", null_array, -1);\n",
- m_ciTemp, escapedName.c_str());
- }
- } else {
- cg_printf("get_call_info_or_fail(cit%d, vt%d, ", m_ciTemp, m_ciTemp);
- cg_printString(m_name, ar, shared_from_this());
- cg_printf(");\n");
- needHash = false;
- }
- } else {
- if (safeCheck) {
- cg_printf("mcp%d.noFatal();\n", m_ciTemp);
- }
- ClassScopePtr cscope = getOriginalClass();
- // The call was like parent::
- string className;
- if (m_classScope) {
- if (isRedeclared()) {
- className = CodeGenerator::FormatLabel(m_className);
- } else {
- className = m_classScope->getId();
- }
- } else {
- className = CodeGenerator::FormatLabel(m_className);
- if (!m_className.empty() && m_cppTemp.empty() &&
- !isSelf() && !isParent() && !isStatic()) {
- // Create a temporary to hold the class name, in case it is not a
- // Static