PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/hphp/compiler/statement/method_statement.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 731 lines | 636 code | 53 blank | 42 comment | 230 complexity | bd73caec64983520d445d76498ce2c9e MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "hphp/compiler/statement/method_statement.h"
  17. #include <folly/Conv.h>
  18. #include <map>
  19. #include <set>
  20. #include "hphp/compiler/statement/return_statement.h"
  21. #include "hphp/compiler/statement/statement_list.h"
  22. #include "hphp/compiler/statement/try_statement.h"
  23. #include "hphp/compiler/statement/label_statement.h"
  24. #include "hphp/compiler/statement/goto_statement.h"
  25. #include "hphp/compiler/statement/exp_statement.h"
  26. #include "hphp/compiler/statement/switch_statement.h"
  27. #include "hphp/compiler/statement/case_statement.h"
  28. #include "hphp/compiler/statement/catch_statement.h"
  29. #include "hphp/compiler/expression/modifier_expression.h"
  30. #include "hphp/compiler/expression/expression_list.h"
  31. #include "hphp/compiler/expression/constant_expression.h"
  32. #include "hphp/compiler/expression/parameter_expression.h"
  33. #include "hphp/compiler/expression/assignment_expression.h"
  34. #include "hphp/compiler/expression/simple_variable.h"
  35. #include "hphp/compiler/expression/closure_expression.h"
  36. #include "hphp/compiler/analysis/ast_walker.h"
  37. #include "hphp/compiler/analysis/analysis_result.h"
  38. #include "hphp/compiler/analysis/code_error.h"
  39. #include "hphp/compiler/analysis/file_scope.h"
  40. #include "hphp/compiler/analysis/variable_table.h"
  41. #include "hphp/compiler/analysis/class_scope.h"
  42. #include "hphp/compiler/analysis/function_scope.h"
  43. #include "hphp/compiler/option.h"
  44. #include "hphp/compiler/builtin_symbols.h"
  45. #include "hphp/compiler/analysis/alias_manager.h"
  46. #include "hphp/parser/parser.h"
  47. #include "hphp/util/text-util.h"
  48. using namespace HPHP;
  49. using std::map;
  50. ///////////////////////////////////////////////////////////////////////////////
  51. // constructors/destructors
  52. MethodStatement::MethodStatement
  53. (STATEMENT_CONSTRUCTOR_BASE_PARAMETERS,
  54. ModifierExpressionPtr modifiers, bool ref, const string &name,
  55. ExpressionListPtr params, TypeAnnotationPtr retTypeAnnotation,
  56. StatementListPtr stmt, int attr, const string &docComment,
  57. ExpressionListPtr attrList, bool method /* = true */)
  58. : Statement(STATEMENT_CONSTRUCTOR_BASE_PARAMETER_VALUES)
  59. , m_method(method)
  60. , m_ref(ref)
  61. , m_hasCallToGetArgs(false)
  62. , m_mayCallSetFrameMetadata(false)
  63. , m_attribute(attr)
  64. , m_cppLength(-1)
  65. , m_autoPropCount(0)
  66. , m_modifiers(modifiers)
  67. , m_name(toLower(name))
  68. , m_originalName(name)
  69. , m_params(params)
  70. , m_retTypeAnnotation(retTypeAnnotation)
  71. , m_stmt(stmt)
  72. , m_docComment(docComment)
  73. , m_attrList(attrList)
  74. {
  75. checkParameters();
  76. }
  77. MethodStatement::MethodStatement
  78. (STATEMENT_CONSTRUCTOR_PARAMETERS,
  79. ModifierExpressionPtr modifiers, bool ref, const string &name,
  80. ExpressionListPtr params, TypeAnnotationPtr retTypeAnnotation,
  81. StatementListPtr stmt, int attr, const string &docComment,
  82. ExpressionListPtr attrList, bool method /* = true */)
  83. : Statement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(MethodStatement))
  84. , m_method(method)
  85. , m_ref(ref)
  86. , m_hasCallToGetArgs(false)
  87. , m_mayCallSetFrameMetadata(false)
  88. , m_attribute(attr)
  89. , m_cppLength(-1)
  90. , m_autoPropCount(0)
  91. , m_modifiers(modifiers)
  92. , m_name(toLower(name))
  93. , m_originalName(name)
  94. , m_params(params)
  95. , m_retTypeAnnotation(retTypeAnnotation)
  96. , m_stmt(stmt)
  97. , m_docComment(docComment)
  98. , m_attrList(attrList)
  99. {
  100. checkParameters();
  101. }
  102. StatementPtr MethodStatement::clone() {
  103. MethodStatementPtr stmt(new MethodStatement(*this));
  104. stmt->m_stmt = Clone(m_stmt);
  105. stmt->m_params = Clone(m_params);
  106. stmt->m_modifiers = Clone(m_modifiers);
  107. return stmt;
  108. }
  109. string MethodStatement::getFullName() const {
  110. if (m_className.empty()) return m_name;
  111. return m_className + "::" + m_name;
  112. }
  113. string MethodStatement::getOriginalFullName() const {
  114. if (m_originalClassName.empty()) return m_originalName;
  115. return m_originalClassName + "::" + m_originalName;
  116. }
  117. bool MethodStatement::isRef(int index /* = -1 */) const {
  118. if (index == -1) return m_ref;
  119. assert(index >= 0 && index < m_params->getCount());
  120. ParameterExpressionPtr param =
  121. dynamic_pointer_cast<ParameterExpression>((*m_params)[index]);
  122. return param->isRef();
  123. }
  124. bool MethodStatement::isSystem() const {
  125. return getFunctionScope()->isSystem();
  126. }
  127. int MethodStatement::getRecursiveCount() const {
  128. return m_stmt ? m_stmt->getRecursiveCount() : 0;
  129. }
  130. ///////////////////////////////////////////////////////////////////////////////
  131. // parser functions
  132. FunctionScopePtr MethodStatement::onInitialParse(AnalysisResultConstPtr ar,
  133. FileScopePtr fs) {
  134. ConstructPtr self = shared_from_this();
  135. int minParam = 0, numDeclParam = 0;
  136. bool hasRef = false;
  137. bool hasVariadicParam = false;
  138. if (m_params) {
  139. std::set<string> names, allDeclNames;
  140. int i = 0;
  141. numDeclParam = m_params->getCount();
  142. ParameterExpressionPtr lastParam =
  143. dynamic_pointer_cast<ParameterExpression>(
  144. (*m_params)[numDeclParam - 1]);
  145. hasVariadicParam = lastParam->isVariadic();
  146. if (hasVariadicParam) {
  147. allDeclNames.insert(lastParam->getName());
  148. // prevent the next loop from visiting the variadic param and testing
  149. // its optionality. parsing ensures that the variadic capture param
  150. // can *only* be the last param.
  151. i = numDeclParam - 2;
  152. } else {
  153. i = numDeclParam - 1;
  154. }
  155. for (; i >= 0; --i) {
  156. ParameterExpressionPtr param =
  157. dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
  158. assert(!param->isVariadic());
  159. if (param->isRef()) { hasRef = true; }
  160. if (!param->isOptional()) {
  161. if (!minParam) minParam = i + 1;
  162. } else if (minParam && !param->hasTypeHint()) {
  163. Compiler::Error(Compiler::RequiredAfterOptionalParam, param);
  164. }
  165. allDeclNames.insert(param->getName());
  166. }
  167. // For the purpose of naming (having entered the the function body), a
  168. // variadic capture param acts as any other variable.
  169. for (i = (numDeclParam - 1); i >= 0; --i) {
  170. ParameterExpressionPtr param =
  171. dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
  172. if (names.find(param->getName()) != names.end()) {
  173. Compiler::Error(Compiler::RedundantParameter, param);
  174. for (int j = 0; j < 1000; j++) {
  175. string name = param->getName() + folly::to<string>(j);
  176. if (names.find(name) == names.end() &&
  177. allDeclNames.find(name) == allDeclNames.end()) {
  178. param->rename(name);
  179. break;
  180. }
  181. }
  182. }
  183. names.insert(param->getName());
  184. }
  185. }
  186. if (hasRef || m_ref) {
  187. m_attribute |= FileScope::ContainsReference;
  188. }
  189. if (hasVariadicParam) {
  190. m_attribute |= FileScope::VariadicArgumentParam;
  191. }
  192. vector<UserAttributePtr> attrs;
  193. if (m_attrList) {
  194. for (int i = 0; i < m_attrList->getCount(); ++i) {
  195. UserAttributePtr a =
  196. dynamic_pointer_cast<UserAttribute>((*m_attrList)[i]);
  197. attrs.push_back(a);
  198. }
  199. }
  200. StatementPtr stmt = dynamic_pointer_cast<Statement>(shared_from_this());
  201. FunctionScopePtr funcScope(
  202. new FunctionScope(ar, m_method, m_name, stmt, m_ref, minParam,
  203. numDeclParam, m_modifiers, m_attribute, m_docComment,
  204. fs, attrs));
  205. if (!m_stmt) {
  206. funcScope->setVirtual();
  207. }
  208. setBlockScope(funcScope);
  209. funcScope->setParamCounts(ar, -1, -1);
  210. if (funcScope->isNative()) {
  211. if ((m_name == "__construct") || (m_name == "__destruct")) {
  212. funcScope->setReturnType(ar, Type::Null);
  213. assert(!m_retTypeAnnotation ||
  214. !m_retTypeAnnotation->dataType().hasValue() ||
  215. (m_retTypeAnnotation->dataType() == KindOfNull));
  216. } else if (m_retTypeAnnotation) {
  217. funcScope->setReturnType(
  218. ar, Type::FromDataType(m_retTypeAnnotation->dataType(), Type::Variant));
  219. } else {
  220. funcScope->setReturnType(ar, Type::Variant);
  221. }
  222. }
  223. return funcScope;
  224. }
  225. void MethodStatement::onParseRecur(AnalysisResultConstPtr ar,
  226. ClassScopePtr classScope) {
  227. FunctionScopeRawPtr fs = getFunctionScope();
  228. const bool isNative = fs->isNative();
  229. if (m_modifiers) {
  230. if ((m_modifiers->isExplicitlyPublic() +
  231. m_modifiers->isProtected() +
  232. m_modifiers->isPrivate()) > 1) {
  233. m_modifiers->parseTimeFatal(
  234. Compiler::InvalidAttribute,
  235. Strings::PICK_ACCESS_MODIFIER
  236. );
  237. }
  238. if (m_modifiers->hasDuplicates()) {
  239. m_modifiers->parseTimeFatal(
  240. Compiler::InvalidAttribute,
  241. Strings::PICK_ACCESS_MODIFIER);
  242. }
  243. if (classScope->isInterface()) {
  244. if (m_modifiers->isProtected() || m_modifiers->isPrivate() ||
  245. m_modifiers->isAbstract() || m_modifiers->isFinal() ||
  246. isNative) {
  247. m_modifiers->parseTimeFatal(
  248. Compiler::InvalidAttribute,
  249. "Access type for interface method %s::%s() must be omitted",
  250. classScope->getOriginalName().c_str(), getOriginalName().c_str());
  251. }
  252. if (m_modifiers->isAsync()) {
  253. m_modifiers->parseTimeFatal(
  254. Compiler::InvalidAttribute,
  255. Strings::ASYNC_WITHOUT_BODY,
  256. "interface", classScope->getOriginalName().c_str(),
  257. getOriginalName().c_str()
  258. );
  259. }
  260. if (getStmts()) {
  261. getStmts()->parseTimeFatal(
  262. Compiler::InvalidMethodDefinition,
  263. "Interface method %s::%s() cannot contain body",
  264. classScope->getOriginalName().c_str(),
  265. getOriginalName().c_str());
  266. }
  267. }
  268. if (m_modifiers->isAbstract()) {
  269. if (m_modifiers->isPrivate() || m_modifiers->isFinal() || isNative) {
  270. m_modifiers->parseTimeFatal(
  271. Compiler::InvalidAttribute,
  272. "Cannot declare abstract method %s::%s() %s",
  273. classScope->getOriginalName().c_str(),
  274. getOriginalName().c_str(),
  275. m_modifiers->isPrivate() ? "private" :
  276. (m_modifiers->isFinal() ? "final" : "native"));
  277. }
  278. if (!classScope->isInterface() && !classScope->isAbstract()) {
  279. /* note that classScope->isAbstract() returns true for traits */
  280. m_modifiers->parseTimeFatal(Compiler::InvalidAttribute,
  281. "Class %s contains abstract method %s and "
  282. "must therefore be declared abstract",
  283. classScope->getOriginalName().c_str(),
  284. getOriginalName().c_str());
  285. }
  286. if (getStmts()) {
  287. parseTimeFatal(Compiler::InvalidAttribute,
  288. "Abstract method %s::%s() cannot contain body",
  289. classScope->getOriginalName().c_str(),
  290. getOriginalName().c_str());
  291. }
  292. if (m_modifiers->isAsync()) {
  293. m_modifiers->parseTimeFatal(
  294. Compiler::InvalidAttribute,
  295. Strings::ASYNC_WITHOUT_BODY,
  296. "abstract", classScope->getOriginalName().c_str(),
  297. getOriginalName().c_str()
  298. );
  299. }
  300. }
  301. if (!m_modifiers->isStatic() && classScope->isStaticUtil()) {
  302. m_modifiers->parseTimeFatal(
  303. Compiler::InvalidAttribute,
  304. "Class %s contains non-static method %s and "
  305. "therefore cannot be declared 'abstract final'",
  306. classScope->getOriginalName().c_str(),
  307. getOriginalName().c_str()
  308. );
  309. }
  310. if (isNative) {
  311. if (getStmts()) {
  312. parseTimeFatal(Compiler::InvalidAttribute,
  313. "Native method %s::%s() cannot contain body",
  314. classScope->getOriginalName().c_str(),
  315. getOriginalName().c_str());
  316. }
  317. auto is_ctordtor = (m_name == "__construct") || (m_name == "__destruct");
  318. if (!m_retTypeAnnotation && !is_ctordtor) {
  319. parseTimeFatal(Compiler::InvalidAttribute,
  320. "Native method %s::%s() must have a return type hint",
  321. classScope->getOriginalName().c_str(),
  322. getOriginalName().c_str());
  323. } else if (m_retTypeAnnotation &&
  324. is_ctordtor &&
  325. (m_retTypeAnnotation->dataType() != KindOfNull)) {
  326. parseTimeFatal(Compiler::InvalidAttribute,
  327. "Native method %s::%s() must return void",
  328. classScope->getOriginalName().c_str(),
  329. getOriginalName().c_str());
  330. }
  331. }
  332. }
  333. if ((!m_modifiers || !m_modifiers->isAbstract()) &&
  334. !getStmts() && !classScope->isInterface() && !isNative) {
  335. parseTimeFatal(Compiler::InvalidAttribute,
  336. "Non-abstract method %s::%s() must contain body",
  337. classScope->getOriginalName().c_str(),
  338. getOriginalName().c_str());
  339. }
  340. classScope->addFunction(ar, fs);
  341. m_className = classScope->getName();
  342. m_originalClassName = classScope->getOriginalName();
  343. setSpecialMethod(classScope);
  344. if (Option::DynamicInvokeFunctions.find(getFullName()) !=
  345. Option::DynamicInvokeFunctions.end()) {
  346. fs->setDynamicInvoke();
  347. }
  348. if (m_params) {
  349. auto nParams = m_params->getCount();
  350. for (int i = 0; i < nParams; i++) {
  351. ParameterExpressionPtr param =
  352. dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
  353. param->parseHandler(classScope);
  354. // Variadic capture params don't need types because they'll
  355. // be treated as Arrays as far as HNI is concerned.
  356. if (isNative && !param->hasUserType() && !param->isVariadic()) {
  357. parseTimeFatal(Compiler::InvalidAttribute,
  358. "Native method calls must have type hints on all args");
  359. }
  360. }
  361. }
  362. FunctionScope::RecordFunctionInfo(m_name, fs);
  363. }
  364. void MethodStatement::fixupSelfAndParentTypehints(ClassScopePtr scope) {
  365. if (m_params) {
  366. for (int i = 0; i < m_params->getCount(); i++) {
  367. ParameterExpressionPtr param =
  368. dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
  369. param->fixupSelfAndParentTypehints(scope);
  370. }
  371. }
  372. }
  373. void MethodStatement::setSpecialMethod(ClassScopePtr classScope) {
  374. if (m_name.size() < 2 || m_name.substr(0,2) != "__") {
  375. return;
  376. }
  377. int numArgs = -1;
  378. bool isStatic = false;
  379. if (m_name == "__construct") {
  380. classScope->setAttribute(ClassScope::HasConstructor);
  381. } else if (m_name == "__destruct") {
  382. classScope->setAttribute(ClassScope::HasDestructor);
  383. if (m_params && m_params->getCount()) {
  384. parseTimeFatal(Compiler::InvalidMagicMethod,
  385. "Method %s::%s() cannot take any arguments",
  386. m_originalClassName.c_str(), m_originalName.c_str());
  387. }
  388. } else if (m_name == "__get") {
  389. classScope->setAttribute(ClassScope::HasUnknownPropGetter);
  390. numArgs = 1;
  391. } else if (m_name == "__set") {
  392. classScope->setAttribute(ClassScope::HasUnknownPropSetter);
  393. numArgs = 2;
  394. } else if (m_name == "__isset") {
  395. classScope->setAttribute(ClassScope::HasUnknownPropTester);
  396. numArgs = 1;
  397. } else if (m_name == "__unset") {
  398. classScope->setAttribute(ClassScope::HasPropUnsetter);
  399. numArgs = 1;
  400. } else if (m_name == "__call") {
  401. classScope->setAttribute(ClassScope::HasUnknownMethodHandler);
  402. numArgs = 2;
  403. } else if (m_name == "__callstatic") {
  404. classScope->setAttribute(ClassScope::HasUnknownStaticMethodHandler);
  405. numArgs = 2;
  406. isStatic = true;
  407. } else if (m_name == "__invoke") {
  408. classScope->setAttribute(ClassScope::HasInvokeMethod);
  409. } else if (m_name == "__tostring") {
  410. numArgs = 0;
  411. } else if (m_name == "__clone") {
  412. if (m_params && m_params->getCount()) {
  413. parseTimeFatal(Compiler::InvalidMagicMethod,
  414. "Method %s::%s() cannot accept any arguments",
  415. m_originalClassName.c_str(), m_originalName.c_str());
  416. }
  417. }
  418. if (numArgs >= 0) {
  419. // Fatal if the number of arguments is wrong
  420. int n = m_params ? m_params->getCount() : 0;
  421. if (numArgs != n) {
  422. parseTimeFatal(Compiler::InvalidMagicMethod,
  423. "Method %s::%s() must take exactly %d argument%s",
  424. m_originalClassName.c_str(), m_originalName.c_str(),
  425. numArgs, (numArgs == 1) ? "" : "s");
  426. }
  427. // Fatal if any arguments are pass by reference
  428. if (m_params && hasRefParam()) {
  429. parseTimeFatal(Compiler::InvalidMagicMethod,
  430. "Method %s::%s() cannot take arguments by reference",
  431. m_originalClassName.c_str(), m_originalName.c_str());
  432. }
  433. // Fatal if any arguments are variadic
  434. if (m_params && getFunctionScope()->hasVariadicParam()) {
  435. parseTimeFatal(Compiler::InvalidMagicMethod,
  436. "Method %s::%s() cannot take a variadic argument",
  437. m_originalClassName.c_str(), m_originalName.c_str());
  438. }
  439. // Fatal if protected/private or if the staticness is wrong
  440. if (m_modifiers->isProtected() || m_modifiers->isPrivate() ||
  441. m_modifiers->isStatic() != isStatic) {
  442. parseTimeFatal(Compiler::InvalidMagicMethod,
  443. "Method %s::%s() must have public visibility and %sbe static",
  444. m_originalClassName.c_str(), m_originalName.c_str(),
  445. isStatic ? "" : "cannot ");
  446. }
  447. }
  448. }
  449. void MethodStatement::addTraitMethodToScope(AnalysisResultConstPtr ar,
  450. ClassScopePtr classScope) {
  451. FunctionScopeRawPtr funcScope = getFunctionScope();
  452. classScope->addFunction(ar, funcScope);
  453. setSpecialMethod(classScope);
  454. FunctionScope::RecordFunctionInfo(m_name, funcScope);
  455. }
  456. ///////////////////////////////////////////////////////////////////////////////
  457. // static analysis functions
  458. int MethodStatement::getLocalEffects() const {
  459. if (m_method) return NoEffect;
  460. FunctionScopeRawPtr scope = getFunctionScope();
  461. return scope->isVolatile() ? OtherEffect | CanThrow : NoEffect;
  462. }
  463. void MethodStatement::analyzeProgram(AnalysisResultPtr ar) {
  464. FunctionScopeRawPtr funcScope = getFunctionScope();
  465. if (m_params) {
  466. m_params->analyzeProgram(ar);
  467. }
  468. if (m_stmt) m_stmt->analyzeProgram(ar);
  469. if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
  470. if (Option::IsDynamicFunction(m_method, m_name) || Option::AllDynamic) {
  471. funcScope->setDynamic();
  472. }
  473. // TODO: this may have to expand to a concept of "virtual" functions...
  474. if (m_method) {
  475. if (m_name.length() > 2 && m_name.substr(0,2) == "__") {
  476. bool magic = true;
  477. int paramCount = 0;
  478. if (m_name == "__destruct") {
  479. funcScope->setOverriding(Type::Variant);
  480. } else if (m_name == "__call") {
  481. funcScope->setOverriding(Type::Variant, Type::String, Type::Array);
  482. paramCount = 2;
  483. } else if (m_name == "__set") {
  484. funcScope->setOverriding(Type::Variant, Type::String, Type::Variant);
  485. paramCount = 2;
  486. } else if (m_name == "__get") {
  487. funcScope->setOverriding(Type::Variant, Type::String);
  488. paramCount = 1;
  489. } else if (m_name == "__isset") {
  490. funcScope->setOverriding(Type::Boolean, Type::String);
  491. paramCount = 1;
  492. } else if (m_name == "__unset") {
  493. funcScope->setOverriding(Type::Variant, Type::String);
  494. paramCount = 1;
  495. } else if (m_name == "__sleep") {
  496. funcScope->setOverriding(Type::Variant);
  497. } else if (m_name == "__wakeup") {
  498. funcScope->setOverriding(Type::Variant);
  499. } else if (m_name == "__set_state") {
  500. funcScope->setOverriding(Type::Variant, Type::Variant);
  501. paramCount = 1;
  502. } else if (m_name == "__tostring") {
  503. // do nothing
  504. } else if (m_name == "__clone") {
  505. funcScope->setOverriding(Type::Variant);
  506. } else {
  507. paramCount = -1;
  508. if (m_name != "__construct") {
  509. magic = false;
  510. }
  511. }
  512. if (paramCount >= 0 && paramCount != funcScope->getMaxParamCount()) {
  513. Compiler::Error(Compiler::InvalidMagicMethod, shared_from_this());
  514. magic = false;
  515. }
  516. if (magic) funcScope->setMagicMethod();
  517. }
  518. // ArrayAccess methods
  519. else if (m_name.length() > 6 && m_name.substr(0, 6) == "offset") {
  520. if (m_name == "offsetexists") {
  521. funcScope->setOverriding(Type::Boolean, Type::Variant);
  522. } else if (m_name == "offsetget") {
  523. funcScope->setOverriding(Type::Variant, Type::Variant);
  524. } else if (m_name == "offsetset") {
  525. funcScope->setOverriding(Type::Variant, Type::Variant, Type::Variant);
  526. } else if (m_name == "offsetunset") {
  527. funcScope->setOverriding(Type::Variant, Type::Variant);
  528. }
  529. }
  530. }
  531. }
  532. }
  533. ConstructPtr MethodStatement::getNthKid(int n) const {
  534. switch (n) {
  535. case 0:
  536. return m_modifiers;
  537. case 1:
  538. return m_params;
  539. case 2:
  540. return m_stmt;
  541. default:
  542. assert(false);
  543. break;
  544. }
  545. return ConstructPtr();
  546. }
  547. int MethodStatement::getKidCount() const {
  548. return 3;
  549. }
  550. void MethodStatement::setNthKid(int n, ConstructPtr cp) {
  551. switch (n) {
  552. case 0:
  553. m_modifiers = dynamic_pointer_cast<ModifierExpression>(cp);
  554. break;
  555. case 1:
  556. m_params = dynamic_pointer_cast<ExpressionList>(cp);
  557. break;
  558. case 2:
  559. m_stmt = dynamic_pointer_cast<StatementList>(cp);
  560. break;
  561. default:
  562. assert(false);
  563. break;
  564. }
  565. }
  566. ///////////////////////////////////////////////////////////////////////////////
  567. void MethodStatement::outputCodeModel(CodeGenerator &cg) {
  568. auto isAnonymous = ParserBase::IsClosureName(m_name);
  569. auto numProps = 4;
  570. if (m_attrList != nullptr) numProps++;
  571. if (m_ref) numProps++;
  572. if (m_params != nullptr) numProps++;
  573. if (m_retTypeAnnotation != nullptr) numProps++;
  574. if (!m_docComment.empty()) numProps++;
  575. cg.printObjectHeader("FunctionStatement", numProps);
  576. if (m_attrList != nullptr) {
  577. cg.printPropertyHeader("attributes");
  578. cg.printExpressionVector(m_attrList);
  579. }
  580. cg.printPropertyHeader("modifiers");
  581. m_modifiers->outputCodeModel(cg);
  582. if (m_ref) {
  583. cg.printPropertyHeader("returnsReference");
  584. cg.printBool(true);
  585. }
  586. cg.printPropertyHeader("name");
  587. cg.printValue(isAnonymous ? "" : m_originalName);
  588. //TODO: type parameters (task 3262469)
  589. if (m_params != nullptr) {
  590. cg.printPropertyHeader("parameters");
  591. cg.printExpressionVector(m_params);
  592. }
  593. if (m_retTypeAnnotation != nullptr) {
  594. cg.printPropertyHeader("returnType");
  595. m_retTypeAnnotation->outputCodeModel(cg);
  596. }
  597. cg.printPropertyHeader("block");
  598. if (m_stmt != nullptr) {
  599. auto stmt = m_stmt;
  600. if (m_autoPropCount > 0) {
  601. stmt = static_pointer_cast<StatementList>(stmt->clone());
  602. for (int i = m_autoPropCount; i > 0; i--) {
  603. stmt->removeElement(0);
  604. }
  605. }
  606. cg.printAsEnclosedBlock(stmt);
  607. } else {
  608. cg.printAsBlock(nullptr);
  609. }
  610. cg.printPropertyHeader("sourceLocation");
  611. cg.printLocation(this->getLocation());
  612. if (!m_docComment.empty()) {
  613. cg.printPropertyHeader("comments");
  614. cg.printValue(m_docComment);
  615. }
  616. cg.printObjectFooter();
  617. }
  618. ///////////////////////////////////////////////////////////////////////////////
  619. // code generation functions
  620. void MethodStatement::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  621. FunctionScopeRawPtr funcScope = getFunctionScope();
  622. m_modifiers->outputPHP(cg, ar);
  623. cg_printf("function ");
  624. if (m_ref) cg_printf("&");
  625. if (!ParserBase::IsClosureName(m_name)) {
  626. cg_printf("%s", m_originalName.c_str());
  627. }
  628. cg_printf("(");
  629. if (m_params) m_params->outputPHP(cg, ar);
  630. if (m_stmt) {
  631. cg_indentBegin(") {\n");
  632. funcScope->outputPHP(cg, ar);
  633. m_stmt->outputPHP(cg, ar);
  634. cg_indentEnd("}\n");
  635. } else {
  636. cg_printf(");\n");
  637. }
  638. }
  639. bool MethodStatement::hasRefParam() {
  640. for (int i = 0; i < m_params->getCount(); i++) {
  641. ParameterExpressionPtr param =
  642. dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
  643. if (param->isRef()) return true;
  644. }
  645. return false;
  646. }
  647. void MethodStatement::checkParameters() {
  648. // only allow parameter modifiers (public, private, protected)
  649. // on constructor for promotion
  650. if (!m_params) {
  651. return;
  652. }
  653. bool isCtor = m_name == "__construct";
  654. for (int i = 0; i < m_params->getCount(); i++) {
  655. auto param =
  656. dynamic_pointer_cast<ParameterExpression>((*m_params)[i]);
  657. switch (param->getModifier()) {
  658. case 0:
  659. continue;
  660. case T_PUBLIC:
  661. case T_PRIVATE:
  662. case T_PROTECTED:
  663. if (isCtor) {
  664. m_autoPropCount++;
  665. continue;
  666. }
  667. default:
  668. if (isCtor) {
  669. param->parseTimeFatal(Compiler::InvalidAttribute,
  670. "Invalid modifier on __construct, only public, "
  671. "private or protected allowed");
  672. } else {
  673. param->parseTimeFatal(Compiler::InvalidAttribute,
  674. "Parameters modifiers not allowed on methods");
  675. }
  676. }
  677. }
  678. }