void ClosureExpression::initializeFromUseList(ExpressionListPtr vars) { m_vars = ExpressionListPtr( new ExpressionList(vars->getScope(), vars->getRange())); // Because PHP is insane you can have a use variable with the same // name as a param name. // In that case, params win (which is different than zend but much easier) auto seenBefore = collectParamNames(); for (int i = vars->getCount() - 1; i >= 0; i--) { auto param = dynamic_pointer_cast<ParameterExpression>((*vars)[i]); assert(param); if (param->getName() == "this") { // "this" is automatically included. // Once we get rid of all the callsites, make this an error continue; } if (seenBefore.find(param->getName().c_str()) == seenBefore.end()) { seenBefore.insert(param->getName().c_str()); m_vars->insertElement(param); } } initializeValuesFromVars(); }
void ClosureExpression::processLambda(AnalysisResultConstRawPtr ar) { if (m_captureState == CaptureState::Unknown) { assert(m_type == ClosureType::Short); auto const closureFuncScope = m_func->getFunctionScope(); auto const paramNames = collectParamNames(); auto const& mentioned = closureFuncScope->getLocals(); std::set<std::string> toCapture; for (auto& m : mentioned) { if (paramNames.count(m)) continue; if (m == "this") { toCapture.insert("this"); continue; } auto scope = closureFuncScope; do { auto const prev = scope; scope = prev->getOuterScope()->getContainingFunction(); always_assert(scope); always_assert(!FileScope::getCurrent() || scope->getContainingFile() == FileScope::getCurrent()); if (scope->hasLocal(m)) { toCapture.insert(m); break; } } while (scope->isLambdaClosure()); } if (closureFuncScope->containsThis()) { toCapture.insert("this"); } setCaptureList(ar, toCapture); } }