MethodStatementPtr ClassScope::importTraitMethod(const TraitMethod& traitMethod, AnalysisResultPtr ar, string methName, const std::map<string, MethodStatementPtr>& importedTraitMethods) { MethodStatementPtr meth = traitMethod.m_method; string origMethName = traitMethod.m_originalName; ModifierExpressionPtr modifiers = traitMethod.m_modifiers; MethodStatementPtr cloneMeth = dynamic_pointer_cast<MethodStatement>( dynamic_pointer_cast<ClassStatement>(m_stmt)->addClone(meth)); cloneMeth->setName(methName); cloneMeth->setOriginalName(origMethName); // Note: keep previous modifiers if none specified when importing the trait if (modifiers && modifiers->getCount()) { cloneMeth->setModifiers(modifiers); } FunctionScopePtr funcScope = meth->getFunctionScope(); // Trait method typehints, self and parent, need to be converted ClassScopePtr cScope = dynamic_pointer_cast<ClassScope>(shared_from_this()); cloneMeth->fixupSelfAndParentTypehints( cScope ); FunctionScopePtr cloneFuncScope (new HPHP::FunctionScope(funcScope, ar, methName, origMethName, cloneMeth, cloneMeth->getModifiers(), cScope->isUserClass())); cloneMeth->resetScope(cloneFuncScope, true); cloneFuncScope->setOuterScope(shared_from_this()); informClosuresAboutScopeClone(cloneMeth, cloneFuncScope, ar); cloneMeth->addTraitMethodToScope(ar, dynamic_pointer_cast<ClassScope>(shared_from_this())); // Preserve original filename (as this varies per-function and not per-unit // in the case of methods imported from flattened traits) cloneMeth->setOriginalFilename(meth->getFileScope()->getName()); return cloneMeth; }
void makeFatalMeth(FileScope& file, AnalysisResultConstPtr ar, const std::string& msg, int line, Meth meth) { auto labelScope = std::make_shared<LabelScope>(); auto r = Location::Range(line, 0, line, 0); BlockScopePtr scope; auto args = std::make_shared<ExpressionList>(scope, r); args->addElement(Expression::MakeScalarExpression(ar, scope, r, msg)); auto e = std::make_shared<SimpleFunctionCall>(scope, r, "throw_fatal", false, args, ExpressionPtr()); meth(e); auto exp = std::make_shared<ExpStatement>(scope, labelScope, r, e); auto stmts = std::make_shared<StatementList>(scope, labelScope, r); stmts->addElement(exp); FunctionScopePtr fs = file.setTree(ar, stmts); fs->setOuterScope(file.shared_from_this()); fs->getStmt()->resetScope(fs); exp->copyLocationTo(fs->getStmt()); file.setOuterScope(const_cast<AnalysisResult*>(ar.get())->shared_from_this()); }
// Rewrite the outermost select clause so that it references properties of // a result tuple constructed by the query provider. Then wrap this expression // in a lambda so that the query provider can invoke it as a call back every // time it produces a result tuple (row). ClosureExpressionPtr QueryExpression::clientSideRewrite( AnalysisResultPtr ar, FileScopePtr fileScope) { // Rewrite the select expression into an expression that refers to // table columns (including computed columns) via properties of an // object produced by the query provider at runtime. ClientSideSelectRewriter cs; cs.rewriteQuery(static_pointer_cast<QueryExpression>(shared_from_this())); auto csSelect = cs.getClientSideSelectClause(); // null if there is no select clause. if (csSelect == nullptr) return nullptr; ExpressionPtr selectExpr = csSelect->getExpression(); // Now wrap up the rewritten expression into a lambda expression that // is passed to the query provider. When the query result is iterated, // the closure is called for each row in the query result in order to // produce the value specified by this select expression. // Create a return statement for the lambda body LabelScopePtr labelScope(new LabelScope()); ReturnStatementPtr returnStatement( new ReturnStatement(BlockScopePtr(), labelScope, getRange(), selectExpr) ); // Wrap up the return statement in a list for the lambda body StatementListPtr stmt( new StatementList(BlockScopePtr(), labelScope, getRange()) ); stmt->addElement(returnStatement); // Create a function statement for the lambda: // First create a formal parameter list, consisting of a single // parameter that will receive an object from the query provider // with a property for each table column that is referenced in the // expression of this select clause. TypeAnnotationPtr type; bool hhType = true; std::string paramName = "__query_result_row__"; bool byRefParam = false; TokenID modifier = 0; ExpressionPtr defaultValue; ExpressionPtr attributeList; ParameterExpressionPtr parameter ( new ParameterExpression(BlockScopePtr(), getRange(), type, hhType, paramName, byRefParam, modifier, defaultValue, attributeList) ); ExpressionListPtr params(new ExpressionList(BlockScopePtr(), getRange())); params->addElement(parameter); // Now create a function statement object ModifierExpressionPtr modifiers( new ModifierExpression(BlockScopePtr(), getRange()) ); bool ref = false; static int counter = 0; std::string name = "__select__#" + std::to_string(counter++); TypeAnnotationPtr retTypeAnnotation; int attr = 0; std::string docComment; ExpressionListPtr attrList; FunctionStatementPtr func( new FunctionStatement(BlockScopePtr(), labelScope, getRange(), modifiers, ref, name, params, retTypeAnnotation, stmt, attr, docComment, attrList) ); // The function statement needs a scope std::vector<UserAttributePtr> uattrs; FunctionScopePtr funcScope (new FunctionScope(ar, false, name, func, false, 1, 1, nullptr, attr, docComment, fileScope, uattrs)); fileScope->addFunction(ar, funcScope); func->resetScope(funcScope); funcScope->setOuterScope(fileScope); // Now construct a closure expression to create the closure value to // pass to the query provider. ExpressionListPtr captures; ClosureExpressionPtr closure( new ClosureExpression(BlockScopePtr(), getRange(), ClosureType::Short, func, captures) ); closure->getClosureFunction()->setContainingClosure(closure); return closure; }