PageRenderTime 24ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/compiler/analysis/class_scope.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 1263 lines | 1047 code | 150 blank | 66 comment | 291 complexity | 7034f5aaa0d9a0bf236b9a58ab9d5645 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/analysis/class_scope.h"
  17. #include "hphp/compiler/analysis/analysis_result.h"
  18. #include "hphp/compiler/analysis/code_error.h"
  19. #include "hphp/compiler/analysis/constant_table.h"
  20. #include "hphp/compiler/analysis/file_scope.h"
  21. #include "hphp/compiler/analysis/function_scope.h"
  22. #include "hphp/compiler/analysis/variable_table.h"
  23. #include "hphp/compiler/construct.h"
  24. #include "hphp/compiler/expression/class_constant_expression.h"
  25. #include "hphp/compiler/expression/closure_expression.h"
  26. #include "hphp/compiler/expression/constant_expression.h"
  27. #include "hphp/compiler/expression/scalar_expression.h"
  28. #include "hphp/compiler/expression/simple_function_call.h"
  29. #include "hphp/compiler/expression/unary_op_expression.h"
  30. #include "hphp/compiler/option.h"
  31. #include "hphp/compiler/parser/parser.h"
  32. #include "hphp/compiler/statement/class_constant.h"
  33. #include "hphp/compiler/statement/class_require_statement.h"
  34. #include "hphp/compiler/statement/class_variable.h"
  35. #include "hphp/compiler/statement/function_statement.h"
  36. #include "hphp/compiler/statement/interface_statement.h"
  37. #include "hphp/compiler/statement/method_statement.h"
  38. #include "hphp/compiler/statement/statement_list.h"
  39. #include "hphp/compiler/statement/trait_alias_statement.h"
  40. #include "hphp/compiler/statement/trait_prec_statement.h"
  41. #include "hphp/compiler/statement/use_trait_statement.h"
  42. #include "hphp/runtime/base/builtin-functions.h"
  43. #include "hphp/runtime/base/class-info.h"
  44. #include "hphp/runtime/base/zend-string.h"
  45. #include "hphp/runtime/vm/trait-method-import-data.h"
  46. #include "hphp/util/text-util.h"
  47. #include <folly/Conv.h>
  48. #include <boost/foreach.hpp>
  49. #include <boost/tuple/tuple.hpp>
  50. #include <map>
  51. #include <set>
  52. #include <unordered_set>
  53. #include <utility>
  54. #include <vector>
  55. using namespace HPHP;
  56. using std::map;
  57. ///////////////////////////////////////////////////////////////////////////////
  58. ClassScope::ClassScope(KindOf kindOf, const std::string &name,
  59. const std::string &parent,
  60. const vector<string> &bases,
  61. const std::string &docComment, StatementPtr stmt,
  62. const std::vector<UserAttributePtr> &attrs)
  63. : BlockScope(name, docComment, stmt, BlockScope::ClassScope),
  64. m_parent(parent), m_bases(bases), m_attribute(0), m_redeclaring(-1),
  65. m_kindOf(kindOf), m_derivesFromRedeclaring(Derivation::Normal),
  66. m_traitStatus(NOT_FLATTENED), m_volatile(false),
  67. m_persistent(false), m_derivedByDynamic(false),
  68. m_needsCppCtor(false), m_needsInit(true) {
  69. m_dynamic = Option::IsDynamicClass(m_name);
  70. // dynamic class is also volatile
  71. m_volatile = Option::AllVolatile || m_dynamic;
  72. for (unsigned i = 0; i < attrs.size(); ++i) {
  73. if (m_userAttributes.find(attrs[i]->getName()) != m_userAttributes.end()) {
  74. attrs[i]->parseTimeFatal(Compiler::DeclaredAttributeTwice,
  75. "Redeclared attribute %s",
  76. attrs[i]->getName().c_str());
  77. }
  78. m_userAttributes[attrs[i]->getName()] = attrs[i]->getExp();
  79. }
  80. assert(m_parent.empty() || (!m_bases.empty() && m_bases[0] == m_parent));
  81. }
  82. // System
  83. ClassScope::ClassScope(AnalysisResultPtr ar,
  84. const std::string &name, const std::string &parent,
  85. const std::vector<std::string> &bases,
  86. const FunctionScopePtrVec &methods)
  87. : BlockScope(name, "", StatementPtr(), BlockScope::ClassScope),
  88. m_parent(parent), m_bases(bases),
  89. m_attribute(0), m_redeclaring(-1),
  90. m_kindOf(KindOf::ObjectClass),
  91. m_derivesFromRedeclaring(Derivation::Normal),
  92. m_traitStatus(NOT_FLATTENED), m_dynamic(false),
  93. m_volatile(false), m_persistent(false),
  94. m_derivedByDynamic(false), m_needsCppCtor(false),
  95. m_needsInit(true) {
  96. for (FunctionScopePtr f: methods) {
  97. if (f->getName() == "__construct") setAttribute(HasConstructor);
  98. else if (f->getName() == "__destruct") setAttribute(HasDestructor);
  99. else if (f->getName() == "__get") setAttribute(HasUnknownPropGetter);
  100. else if (f->getName() == "__set") setAttribute(HasUnknownPropSetter);
  101. else if (f->getName() == "__call") setAttribute(HasUnknownMethodHandler);
  102. else if (f->getName() == "__callstatic") {
  103. setAttribute(HasUnknownStaticMethodHandler);
  104. } else if (f->getName() == "__isset") setAttribute(HasUnknownPropTester);
  105. else if (f->getName() == "__unset") setAttribute(HasPropUnsetter);
  106. else if (f->getName() == "__invoke") setAttribute(HasInvokeMethod);
  107. addFunction(ar, f);
  108. }
  109. setAttribute(Extension);
  110. setAttribute(System);
  111. assert(m_parent.empty() || (!m_bases.empty() && m_bases[0] == m_parent));
  112. }
  113. const std::string &ClassScope::getOriginalName() const {
  114. if (m_stmt) {
  115. return dynamic_pointer_cast<InterfaceStatement>(m_stmt)->
  116. getOriginalName();
  117. }
  118. return m_originalName;
  119. }
  120. std::string ClassScope::getDocName() const {
  121. string name = getOriginalName();
  122. if (m_redeclaring < 0) {
  123. return name;
  124. }
  125. return name + Option::IdPrefix + folly::to<std::string>(m_redeclaring);
  126. }
  127. bool ClassScope::NeedStaticArray(ClassScopePtr cls, FunctionScopePtr func) {
  128. return cls && cls->getAttribute(NotFinal) && !func->isPrivate();
  129. }
  130. ///////////////////////////////////////////////////////////////////////////////
  131. void ClassScope::derivedMagicMethods(ClassScopePtr super) {
  132. super->setAttribute(NotFinal);
  133. if (derivedByDynamic()) {
  134. super->m_derivedByDynamic = true;
  135. }
  136. if (m_attribute & (HasUnknownPropGetter|
  137. MayHaveUnknownPropGetter|
  138. InheritsUnknownPropGetter)) {
  139. super->setAttribute(MayHaveUnknownPropGetter);
  140. }
  141. if (m_attribute & (HasUnknownPropSetter|
  142. MayHaveUnknownPropSetter|
  143. InheritsUnknownPropSetter)) {
  144. super->setAttribute(MayHaveUnknownPropSetter);
  145. }
  146. if (m_attribute & (HasUnknownPropTester|
  147. MayHaveUnknownPropTester|
  148. InheritsUnknownPropTester)) {
  149. super->setAttribute(MayHaveUnknownPropTester);
  150. }
  151. if (m_attribute & (HasPropUnsetter|
  152. MayHavePropUnsetter|
  153. InheritsPropUnsetter)) {
  154. super->setAttribute(MayHavePropUnsetter);
  155. }
  156. if (m_attribute & (HasUnknownMethodHandler|
  157. MayHaveUnknownMethodHandler|
  158. InheritsUnknownMethodHandler)) {
  159. super->setAttribute(MayHaveUnknownMethodHandler);
  160. }
  161. if (m_attribute & (HasUnknownStaticMethodHandler|
  162. MayHaveUnknownStaticMethodHandler|
  163. InheritsUnknownStaticMethodHandler)) {
  164. super->setAttribute(MayHaveUnknownStaticMethodHandler);
  165. }
  166. if (m_attribute & (HasInvokeMethod|
  167. MayHaveInvokeMethod|
  168. InheritsInvokeMethod)) {
  169. super->setAttribute(MayHaveInvokeMethod);
  170. }
  171. if (m_attribute & (HasArrayAccess|
  172. MayHaveArrayAccess|
  173. InheritsArrayAccess)) {
  174. super->setAttribute(MayHaveArrayAccess);
  175. }
  176. }
  177. void ClassScope::inheritedMagicMethods(ClassScopePtr super) {
  178. if (super->m_attribute & UsesUnknownTrait) {
  179. setAttribute(UsesUnknownTrait);
  180. }
  181. if (super->m_attribute &
  182. (HasUnknownPropGetter|InheritsUnknownPropGetter)) {
  183. setAttribute(InheritsUnknownPropGetter);
  184. }
  185. if (super->m_attribute & (HasUnknownPropSetter|InheritsUnknownPropSetter)) {
  186. setAttribute(InheritsUnknownPropSetter);
  187. }
  188. if (super->m_attribute & (HasUnknownPropTester|InheritsUnknownPropTester)) {
  189. setAttribute(InheritsUnknownPropTester);
  190. }
  191. if (super->m_attribute & (HasPropUnsetter|InheritsPropUnsetter)) {
  192. setAttribute(InheritsPropUnsetter);
  193. }
  194. if (super->m_attribute &
  195. (HasUnknownMethodHandler|InheritsUnknownMethodHandler)) {
  196. setAttribute(InheritsUnknownMethodHandler);
  197. }
  198. if (super->m_attribute &
  199. (HasUnknownStaticMethodHandler|InheritsUnknownStaticMethodHandler)) {
  200. setAttribute(InheritsUnknownStaticMethodHandler);
  201. }
  202. if (super->m_attribute & (HasInvokeMethod|InheritsInvokeMethod)) {
  203. setAttribute(InheritsInvokeMethod);
  204. }
  205. if (super->m_attribute & (HasArrayAccess|InheritsArrayAccess)) {
  206. setAttribute(InheritsArrayAccess);
  207. }
  208. }
  209. bool ClassScope::implementsArrayAccess() {
  210. return
  211. getAttribute(MayHaveArrayAccess) |
  212. getAttribute(HasArrayAccess) |
  213. getAttribute(InheritsArrayAccess);
  214. }
  215. bool ClassScope::implementsAccessor(int prop) {
  216. if (m_attribute & prop) return true;
  217. if (prop & MayHaveUnknownPropGetter) {
  218. prop |= HasUnknownPropGetter | InheritsUnknownPropGetter;
  219. }
  220. if (prop & MayHaveUnknownPropSetter) {
  221. prop |= HasUnknownPropSetter | InheritsUnknownPropSetter;
  222. }
  223. if (prop & MayHaveUnknownPropTester) {
  224. prop |= HasUnknownPropTester | InheritsUnknownPropTester;
  225. }
  226. if (prop & MayHavePropUnsetter) {
  227. prop |= HasPropUnsetter | InheritsPropUnsetter;
  228. }
  229. return m_attribute & prop;
  230. }
  231. void ClassScope::checkDerivation(AnalysisResultPtr ar, hphp_string_iset &seen) {
  232. seen.insert(m_name);
  233. hphp_string_iset bases;
  234. for (int i = m_bases.size() - 1; i >= 0; i--) {
  235. const string &base = m_bases[i];
  236. if (seen.find(base) != seen.end() || bases.find(base) != bases.end()) {
  237. Compiler::Error(
  238. Compiler::InvalidDerivation,
  239. m_stmt,
  240. "The class hierarchy contains a circular reference involving " + base);
  241. if (i == 0 && !m_parent.empty()) {
  242. assert(base == m_parent);
  243. m_parent.clear();
  244. }
  245. m_bases.erase(m_bases.begin() + i);
  246. continue;
  247. }
  248. bases.insert(base);
  249. ClassScopePtrVec parents = ar->findClasses(toLower(base));
  250. for (unsigned int j = 0; j < parents.size(); j++) {
  251. parents[j]->checkDerivation(ar, seen);
  252. }
  253. }
  254. seen.erase(m_name);
  255. }
  256. void ClassScope::collectMethods(AnalysisResultPtr ar,
  257. StringToFunctionScopePtrMap &funcs,
  258. bool collectPrivate) {
  259. // add all functions this class has
  260. for (FunctionScopePtrVec::const_iterator iter =
  261. m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) {
  262. const FunctionScopePtr &fs = *iter;
  263. if (!collectPrivate && fs->isPrivate()) continue;
  264. FunctionScopePtr &func = funcs[fs->getName()];
  265. if (!func) {
  266. func = fs;
  267. } else {
  268. func->setVirtual();
  269. fs->setVirtual();
  270. fs->setHasOverride();
  271. if (fs->isFinal()) {
  272. std::string s__MockClass = "__MockClass";
  273. ClassScopePtr derivedClass = func->getContainingClass();
  274. if (derivedClass->m_userAttributes.find(s__MockClass) ==
  275. derivedClass->m_userAttributes.end()) {
  276. Compiler::Error(Compiler::InvalidOverride,
  277. fs->getStmt(), func->getStmt());
  278. }
  279. }
  280. }
  281. }
  282. int n = m_bases.size();
  283. for (int i = 0; i < n; i++) {
  284. const string &base = m_bases[i];
  285. ClassScopePtr super = ar->findClass(base);
  286. if (super) {
  287. if (super->isRedeclaring()) {
  288. const ClassScopePtrVec &classes = ar->findRedeclaredClasses(base);
  289. StringToFunctionScopePtrMap pristine(funcs);
  290. for (auto& cls : classes) {
  291. cls->m_derivedByDynamic = true;
  292. StringToFunctionScopePtrMap cur(pristine);
  293. derivedMagicMethods(cls);
  294. cls->collectMethods(ar, cur, false);
  295. inheritedMagicMethods(cls);
  296. funcs.insert(cur.begin(), cur.end());
  297. cls->getVariables()->
  298. forceVariants(ar, VariableTable::AnyNonPrivateVars);
  299. }
  300. m_derivesFromRedeclaring = Derivation::Redeclaring;
  301. getVariables()->forceVariants(ar, VariableTable::AnyNonPrivateVars,
  302. false);
  303. getVariables()->setAttribute(VariableTable::NeedGlobalPointer);
  304. setVolatile();
  305. } else {
  306. derivedMagicMethods(super);
  307. super->collectMethods(ar, funcs, false);
  308. inheritedMagicMethods(super);
  309. if (super->derivesFromRedeclaring() == Derivation::Redeclaring) {
  310. m_derivesFromRedeclaring = Derivation::Redeclaring;
  311. getVariables()->forceVariants(ar, VariableTable::AnyNonPrivateVars);
  312. setVolatile();
  313. } else if (super->isVolatile()) {
  314. setVolatile();
  315. }
  316. }
  317. } else {
  318. Compiler::Error(Compiler::UnknownBaseClass, m_stmt, base);
  319. if (base == m_parent) {
  320. ar->declareUnknownClass(m_parent);
  321. m_derivesFromRedeclaring = Derivation::Redeclaring;
  322. getVariables()->setAttribute(VariableTable::NeedGlobalPointer);
  323. getVariables()->forceVariants(ar, VariableTable::AnyNonPrivateVars);
  324. setVolatile();
  325. } else {
  326. /*
  327. * TODO(#3685260): this should not be removing interfaces from
  328. * the base list.
  329. */
  330. if (isInterface()) {
  331. m_derivesFromRedeclaring = Derivation::Redeclaring;
  332. }
  333. m_bases.erase(m_bases.begin() + i);
  334. n--;
  335. i--;
  336. }
  337. }
  338. }
  339. }
  340. void ClassScope::importTraitProperties(AnalysisResultPtr ar) {
  341. for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
  342. ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
  343. if (!tCls) continue;
  344. ClassStatementPtr tStmt =
  345. dynamic_pointer_cast<ClassStatement>(tCls->getStmt());
  346. StatementListPtr tStmts = tStmt->getStmts();
  347. if (!tStmts) continue;
  348. for (int s = 0; s < tStmts->getCount(); s++) {
  349. ClassVariablePtr prop =
  350. dynamic_pointer_cast<ClassVariable>((*tStmts)[s]);
  351. if (prop) {
  352. ClassVariablePtr cloneProp = dynamic_pointer_cast<ClassVariable>(
  353. dynamic_pointer_cast<ClassStatement>(m_stmt)->addClone(prop));
  354. cloneProp->resetScope(shared_from_this(), true);
  355. cloneProp->addTraitPropsToScope(ar,
  356. dynamic_pointer_cast<ClassScope>(shared_from_this()));
  357. }
  358. }
  359. }
  360. }
  361. MethodStatementPtr
  362. ClassScope::importTraitMethod(const TraitMethod& traitMethod,
  363. AnalysisResultPtr ar,
  364. std::string methName) {
  365. MethodStatementPtr meth = traitMethod.method;
  366. std::string origMethName = traitMethod.originalName;
  367. ModifierExpressionPtr modifiers = traitMethod.modifiers;
  368. MethodStatementPtr cloneMeth = dynamic_pointer_cast<MethodStatement>(
  369. dynamic_pointer_cast<ClassStatement>(m_stmt)->addClone(meth));
  370. cloneMeth->setName(methName);
  371. cloneMeth->setOriginalName(origMethName);
  372. // Note: keep previous modifiers if none specified when importing the trait
  373. if (modifiers && modifiers->getCount()) {
  374. cloneMeth->setModifiers(modifiers);
  375. }
  376. FunctionScopePtr funcScope = meth->getFunctionScope();
  377. // Trait method typehints, self and parent, need to be converted
  378. ClassScopePtr cScope = dynamic_pointer_cast<ClassScope>(shared_from_this());
  379. cloneMeth->fixupSelfAndParentTypehints( cScope );
  380. FunctionScopePtr cloneFuncScope
  381. (new HPHP::FunctionScope(funcScope, ar, methName, origMethName, cloneMeth,
  382. cloneMeth->getModifiers(), cScope->isUserClass()));
  383. cloneMeth->resetScope(cloneFuncScope, true);
  384. cloneFuncScope->setOuterScope(shared_from_this());
  385. informClosuresAboutScopeClone(cloneMeth, cloneFuncScope, ar);
  386. cloneMeth->addTraitMethodToScope(ar,
  387. dynamic_pointer_cast<ClassScope>(shared_from_this()));
  388. // Preserve original filename (as this varies per-function and not per-unit
  389. // in the case of methods imported from flattened traits)
  390. cloneMeth->setOriginalFilename(meth->getFileScope()->getName());
  391. return cloneMeth;
  392. }
  393. void ClassScope::informClosuresAboutScopeClone(
  394. ConstructPtr root,
  395. FunctionScopePtr outerScope,
  396. AnalysisResultPtr ar) {
  397. if (!root) {
  398. return;
  399. }
  400. for (int i = 0; i < root->getKidCount(); i++) {
  401. ConstructPtr cons = root->getNthKid(i);
  402. ClosureExpressionPtr closure =
  403. dynamic_pointer_cast<ClosureExpression>(cons);
  404. if (!closure) {
  405. informClosuresAboutScopeClone(cons, outerScope, ar);
  406. continue;
  407. }
  408. FunctionStatementPtr func = closure->getClosureFunction();
  409. HPHP::FunctionScopePtr funcScope = func->getFunctionScope();
  410. assert(funcScope->isClosure());
  411. funcScope->addClonedTraitOuterScope(outerScope);
  412. // Don't need to recurse
  413. }
  414. }
  415. void ClassScope::addClassRequirement(const string &requiredName,
  416. bool isExtends) {
  417. assert(isTrait() || (isInterface() && isExtends)
  418. // when flattening traits, their requirements get flattened
  419. || Option::WholeProgram);
  420. if (isExtends) {
  421. m_requiredExtends.insert(requiredName);
  422. } else {
  423. m_requiredImplements.insert(requiredName);
  424. }
  425. }
  426. void ClassScope::importClassRequirements(AnalysisResultPtr ar,
  427. ClassScopePtr trait) {
  428. /* Defer enforcement of requirements until the creation of the class
  429. * happens at runtime. */
  430. for (auto const& req : trait->getClassRequiredExtends()) {
  431. addClassRequirement(req, true);
  432. }
  433. for (auto const& req : trait->getClassRequiredImplements()) {
  434. addClassRequirement(req, false);
  435. }
  436. }
  437. bool ClassScope::hasMethod(const string &methodName) const {
  438. return m_functions.find(methodName) != m_functions.end();
  439. }
  440. ///////////////////////////////////////////////////////////////////////////////
  441. // Trait flattening.
  442. namespace {
  443. void findTraitMethodsToImport(AnalysisResultPtr ar,
  444. ClassScopePtr trait,
  445. ClassScope::TMIData& tmid) {
  446. assert(Option::WholeProgram);
  447. ClassStatementPtr tStmt =
  448. dynamic_pointer_cast<ClassStatement>(trait->getStmt());
  449. StatementListPtr tStmts = tStmt->getStmts();
  450. if (!tStmts) return;
  451. for (int s = 0; s < tStmts->getCount(); s++) {
  452. MethodStatementPtr meth =
  453. dynamic_pointer_cast<MethodStatement>((*tStmts)[s]);
  454. if (meth) {
  455. ClassScope::TraitMethod traitMethod(trait, meth,
  456. ModifierExpressionPtr(),
  457. MethodStatementPtr());
  458. tmid.add(traitMethod, meth->getName());
  459. }
  460. }
  461. }
  462. MethodStatementPtr findTraitMethodImpl(AnalysisResultPtr ar,
  463. ClassScopePtr trait,
  464. const std::string& methodName,
  465. std::set<ClassScopePtr>& visitedTraits) {
  466. if (visitedTraits.find(trait) != visitedTraits.end()) {
  467. return MethodStatementPtr();
  468. }
  469. visitedTraits.insert(trait);
  470. ClassStatementPtr tStmt =
  471. dynamic_pointer_cast<ClassStatement>(trait->getStmt());
  472. StatementListPtr tStmts = tStmt->getStmts();
  473. // Look in the current trait.
  474. for (int s = 0; s < tStmts->getCount(); s++) {
  475. MethodStatementPtr meth =
  476. dynamic_pointer_cast<MethodStatement>((*tStmts)[s]);
  477. if (meth) { // handle methods
  478. if (meth->getName() == methodName) {
  479. return meth;
  480. }
  481. }
  482. }
  483. // Look into children traits.
  484. for (int s = 0; s < tStmts->getCount(); s++) {
  485. UseTraitStatementPtr useTraitStmt =
  486. dynamic_pointer_cast<UseTraitStatement>((*tStmts)[s]);
  487. if (useTraitStmt) {
  488. vector<string> usedTraits;
  489. useTraitStmt->getUsedTraitNames(usedTraits);
  490. for (unsigned i = 0; i < usedTraits.size(); i++) {
  491. MethodStatementPtr foundMethod =
  492. findTraitMethodImpl(ar, ar->findClass(usedTraits[i]),
  493. methodName, visitedTraits);
  494. if (foundMethod) return foundMethod;
  495. }
  496. }
  497. }
  498. return MethodStatementPtr(); // not found
  499. }
  500. }
  501. void ClassScope::TMIOps::addTraitAlias(ClassScope* cs,
  502. TraitAliasStatementPtr stmt,
  503. ClassScopePtr traitCls) {
  504. auto const& traitName = stmt->getTraitName();
  505. auto const& origMethName = stmt->getMethodName();
  506. auto const& newMethName = stmt->getNewMethodName();
  507. auto origName = traitName.empty() ? "(null)" : traitName;
  508. origName += "::" + origMethName;
  509. cs->m_traitAliases.push_back(std::make_pair(newMethName, origName));
  510. }
  511. ClassScopePtr
  512. ClassScope::TMIOps::findSingleTraitWithMethod(ClassScope* cs,
  513. const std::string& origMethName) {
  514. ClassScopePtr trait{};
  515. for (auto const& name : cs->m_usedTraitNames) {
  516. ClassScopePtr tCls = cs->getContainingProgram()->findClass(name);
  517. if (!tCls) continue;
  518. if (tCls->hasMethod(origMethName)) {
  519. if (trait) {
  520. // More than one trait contains the method.
  521. return ClassScopePtr();
  522. }
  523. trait = tCls;
  524. }
  525. }
  526. return trait;
  527. }
  528. ClassScopePtr
  529. ClassScope::TMIOps::findTraitClass(ClassScope* cs,
  530. const std::string& traitName) {
  531. return cs->getContainingProgram()->findClass(traitName);
  532. }
  533. MethodStatementPtr
  534. ClassScope::TMIOps::findTraitMethod(ClassScope* cs,
  535. ClassScopePtr traitCls,
  536. const std::string& origMethName) {
  537. std::set<ClassScopePtr> visitedTraits;
  538. return findTraitMethodImpl(cs->getContainingProgram(), traitCls,
  539. origMethName, visitedTraits);
  540. }
  541. void ClassScope::applyTraitRules(TMIData& tmid) {
  542. ClassStatementPtr classStmt =
  543. dynamic_pointer_cast<ClassStatement>(getStmt());
  544. assert(classStmt);
  545. StatementListPtr stmts = classStmt->getStmts();
  546. if (!stmts) return;
  547. for (int s = 0; s < stmts->getCount(); s++) {
  548. StatementPtr stmt = (*stmts)[s];
  549. UseTraitStatementPtr useStmt =
  550. dynamic_pointer_cast<UseTraitStatement>(stmt);
  551. if (!useStmt) continue;
  552. StatementListPtr rules = useStmt->getStmts();
  553. for (int r = 0; r < rules->getCount(); r++) {
  554. StatementPtr rule = (*rules)[r];
  555. TraitPrecStatementPtr precStmt =
  556. dynamic_pointer_cast<TraitPrecStatement>(rule);
  557. if (precStmt) {
  558. tmid.applyPrecRule(precStmt);
  559. } else {
  560. TraitAliasStatementPtr aliasStmt =
  561. dynamic_pointer_cast<TraitAliasStatement>(rule);
  562. assert(aliasStmt);
  563. tmid.applyAliasRule(aliasStmt, this);
  564. }
  565. }
  566. }
  567. }
  568. void ClassScope::importUsedTraits(AnalysisResultPtr ar) {
  569. // Trait flattening is supposed to happen only when we have awareness of the
  570. // whole program.
  571. assert(Option::WholeProgram);
  572. if (m_traitStatus == FLATTENED) return;
  573. if (m_traitStatus == BEING_FLATTENED) {
  574. getStmt()->analysisTimeFatal(
  575. Compiler::CyclicDependentTraits,
  576. "Cyclic dependency between traits involving %s",
  577. getOriginalName().c_str()
  578. );
  579. return;
  580. }
  581. if (m_usedTraitNames.size() == 0) {
  582. m_traitStatus = FLATTENED;
  583. return;
  584. }
  585. m_traitStatus = BEING_FLATTENED;
  586. m_numDeclMethods = m_functionsVec.size();
  587. // First, make sure that parent classes have their traits imported.
  588. if (!m_parent.empty()) {
  589. ClassScopePtr parent = ar->findClass(m_parent);
  590. if (parent) {
  591. parent->importUsedTraits(ar);
  592. }
  593. }
  594. TMIData tmid;
  595. if (isTrait()) {
  596. for (auto const& req : getClassRequiredExtends()) {
  597. ClassScopePtr rCls = ar->findClass(req);
  598. if (!rCls || rCls->isFinal() || rCls->isInterface()) {
  599. getStmt()->analysisTimeFatal(
  600. Compiler::InvalidDerivation,
  601. Strings::TRAIT_BAD_REQ_EXTENDS,
  602. m_originalName.c_str(),
  603. req.c_str(),
  604. req.c_str()
  605. );
  606. }
  607. }
  608. for (auto const& req : getClassRequiredImplements()) {
  609. ClassScopePtr rCls = ar->findClass(req);
  610. if (!rCls || !(rCls->isInterface())) {
  611. getStmt()->analysisTimeFatal(
  612. Compiler::InvalidDerivation,
  613. Strings::TRAIT_BAD_REQ_IMPLEMENTS,
  614. m_originalName.c_str(),
  615. req.c_str(),
  616. req.c_str()
  617. );
  618. }
  619. }
  620. }
  621. // Find trait methods to be imported.
  622. for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
  623. ClassScopePtr tCls = ar->findClass(m_usedTraitNames[i]);
  624. if (!tCls || !(tCls->isTrait())) {
  625. setAttribute(UsesUnknownTrait); // XXX: is this useful ... for anything?
  626. getStmt()->analysisTimeFatal(
  627. Compiler::UnknownTrait,
  628. Strings::TRAITS_UNKNOWN_TRAIT,
  629. m_usedTraitNames[i].c_str()
  630. );
  631. }
  632. // First, make sure the used trait is flattened.
  633. tCls->importUsedTraits(ar);
  634. findTraitMethodsToImport(ar, tCls, tmid);
  635. // Import any interfaces implemented.
  636. tCls->getInterfaces(ar, m_bases, /* recursive */ false);
  637. importClassRequirements(ar, tCls);
  638. }
  639. // Apply rules.
  640. applyTraitRules(tmid);
  641. // Remove methods declared on the current class from the trait import list;
  642. // the class methods take precedence.
  643. for (auto const& methName : tmid.methodNames()) {
  644. if (findFunction(ar, methName, false /* recursive */,
  645. false /* exclIntfBase */)) {
  646. // This does not affect the methodNames() vector.
  647. tmid.erase(methName);
  648. }
  649. }
  650. auto traitMethods = tmid.finish(this);
  651. std::map<string, MethodStatementPtr> importedTraitMethods;
  652. std::vector<std::pair<string,const TraitMethod*>> importedTraitsWithOrigName;
  653. // Actually import the methods.
  654. for (auto const& mdata : traitMethods) {
  655. if ((mdata.tm.modifiers ? mdata.tm.modifiers
  656. : mdata.tm.method->getModifiers()
  657. )->isAbstract()) {
  658. // Skip abstract methods, if the method already exists in the class.
  659. if (findFunction(ar, mdata.name, true) ||
  660. importedTraitMethods.count(mdata.name)) {
  661. continue;
  662. }
  663. }
  664. auto sourceName = mdata.tm.ruleStmt
  665. ? toLower(
  666. ((TraitAliasStatement*)mdata.tm.ruleStmt.get())->getMethodName())
  667. : mdata.name;
  668. importedTraitMethods[sourceName] = MethodStatementPtr();
  669. importedTraitsWithOrigName.push_back(
  670. std::make_pair(sourceName, &mdata.tm));
  671. }
  672. // Make sure there won't be 2 constructors after importing
  673. auto traitConstruct = importedTraitMethods.count("__construct");
  674. auto traitName = importedTraitMethods.count(getName());
  675. auto classConstruct = m_functions.count("__construct");
  676. auto className = m_functions.count(getName());
  677. if ((traitConstruct && traitName) ||
  678. (traitConstruct && className) ||
  679. (classConstruct && traitName)) {
  680. getStmt()->analysisTimeFatal(
  681. Compiler::InvalidDerivation,
  682. "%s has colliding constructor definitions coming from traits",
  683. getOriginalName().c_str()
  684. );
  685. }
  686. for (auto const& traitPair : importedTraitsWithOrigName) {
  687. auto traitMethod = traitPair.second;
  688. MethodStatementPtr newMeth = importTraitMethod(
  689. *traitMethod,
  690. ar,
  691. toLower(traitMethod->originalName)
  692. );
  693. }
  694. // Import trait properties
  695. importTraitProperties(ar);
  696. m_traitStatus = FLATTENED;
  697. }
  698. ///////////////////////////////////////////////////////////////////////////////
  699. bool ClassScope::usesTrait(const string &traitName) const {
  700. for (unsigned i = 0; i < m_usedTraitNames.size(); i++) {
  701. if (traitName == m_usedTraitNames[i]) {
  702. return true;
  703. }
  704. }
  705. return false;
  706. }
  707. bool ClassScope::needsInvokeParent(AnalysisResultConstPtr ar,
  708. bool considerSelf /* = true */) {
  709. // check all functions this class has
  710. if (considerSelf) {
  711. for (FunctionScopePtrVec::const_iterator iter =
  712. m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) {
  713. if ((*iter)->isPrivate()) return true;
  714. }
  715. }
  716. // walk up
  717. if (!m_parent.empty()) {
  718. ClassScopePtr super = ar->findClass(m_parent);
  719. return !super || super->isRedeclaring() || super->needsInvokeParent(ar);
  720. }
  721. return false;
  722. }
  723. bool ClassScope::derivesDirectlyFrom(const std::string &base) const {
  724. for (std::string base_i: m_bases) {
  725. if (strcasecmp(base_i.c_str(), base.c_str()) == 0) return true;
  726. }
  727. return false;
  728. }
  729. bool ClassScope::derivesFrom(AnalysisResultConstPtr ar,
  730. const std::string &base,
  731. bool strict, bool def) const {
  732. if (derivesDirectlyFrom(base)) return true;
  733. for (std::string base_i: m_bases) {
  734. ClassScopePtr cl = ar->findClass(base_i);
  735. if (cl) {
  736. if (strict && cl->isRedeclaring()) {
  737. if (def) return true;
  738. continue;
  739. }
  740. if (cl->derivesFrom(ar, base, strict, def)) return true;
  741. }
  742. }
  743. return false;
  744. }
  745. ClassScopePtr ClassScope::FindCommonParent(AnalysisResultConstPtr ar,
  746. const std::string &cn1,
  747. const std::string &cn2) {
  748. ClassScopePtr cls1 = ar->findClass(cn1);
  749. ClassScopePtr cls2 = ar->findClass(cn2);
  750. if (!cls1 || !cls2) return ClassScopePtr();
  751. if (cls1->getName() == cls2->getName()) return cls1;
  752. if (cls1->derivesFrom(ar, cn2, true, false)) return cls2;
  753. if (cls2->derivesFrom(ar, cn1, true, false)) return cls1;
  754. // walk up the class hierarchy.
  755. for (const std::string &base1: cls1->m_bases) {
  756. for (const std::string &base2: cls2->m_bases) {
  757. ClassScopePtr parent = FindCommonParent(ar, base1, base2);
  758. if (parent) return parent;
  759. }
  760. }
  761. return ClassScopePtr();
  762. }
  763. void ClassScope::setVolatile() {
  764. if (!m_volatile) {
  765. m_volatile = true;
  766. Lock lock(s_depsMutex);
  767. const BlockScopeRawPtrFlagsVec &orderedUsers = getOrderedUsers();
  768. for (BlockScopeRawPtrFlagsVec::const_iterator it = orderedUsers.begin(),
  769. end = orderedUsers.end(); it != end; ++it) {
  770. BlockScopeRawPtrFlagsVec::value_type pf = *it;
  771. if (pf->second & UseKindParentRef) {
  772. BlockScopeRawPtr scope = pf->first;
  773. if (scope->is(BlockScope::ClassScope)) {
  774. ((HPHP::ClassScope*)scope.get())->setVolatile();
  775. }
  776. }
  777. }
  778. }
  779. }
  780. FunctionScopePtr ClassScope::findFunction(AnalysisResultConstPtr ar,
  781. const std::string &name,
  782. bool recursive,
  783. bool exclIntfBase /* = false */) {
  784. assert(toLower(name) == name);
  785. StringToFunctionScopePtrMap::const_iterator iter;
  786. iter = m_functions.find(name);
  787. if (iter != m_functions.end()) {
  788. assert(iter->second);
  789. return iter->second;
  790. }
  791. // walk up
  792. if (recursive) {
  793. int s = m_bases.size();
  794. for (int i = 0; i < s; i++) {
  795. const string &base = m_bases[i];
  796. ClassScopePtr super = ar->findClass(base);
  797. if (!super) continue;
  798. if (exclIntfBase && super->isInterface()) break;
  799. if (super->isRedeclaring()) {
  800. if (base == m_parent) {
  801. m_derivesFromRedeclaring = Derivation::Redeclaring;
  802. break;
  803. }
  804. continue;
  805. }
  806. FunctionScopePtr func =
  807. super->findFunction(ar, name, true, exclIntfBase);
  808. if (func) return func;
  809. }
  810. }
  811. if (!Option::AllDynamic &&
  812. derivesFromRedeclaring() == Derivation::Redeclaring) {
  813. setDynamic(ar, name);
  814. }
  815. return FunctionScopePtr();
  816. }
  817. FunctionScopePtr ClassScope::findConstructor(AnalysisResultConstPtr ar,
  818. bool recursive) {
  819. StringToFunctionScopePtrMap::const_iterator iter;
  820. string name;
  821. if (classNameCtor()) {
  822. name = getName();
  823. } else {
  824. name = "__construct";
  825. }
  826. iter = m_functions.find(name);
  827. if (iter != m_functions.end()) {
  828. assert(iter->second);
  829. return iter->second;
  830. }
  831. // walk up
  832. if (recursive && derivesFromRedeclaring() != Derivation::Redeclaring) {
  833. ClassScopePtr super = ar->findClass(m_parent);
  834. if (super) {
  835. FunctionScopePtr func = super->findConstructor(ar, true);
  836. if (func) return func;
  837. }
  838. }
  839. if (!Option::AllDynamic &&
  840. derivesFromRedeclaring() == Derivation::Redeclaring) {
  841. setDynamic(ar, name);
  842. }
  843. return FunctionScopePtr();
  844. }
  845. void ClassScope::setStaticDynamic(AnalysisResultConstPtr ar) {
  846. for (FunctionScopePtrVec::const_iterator iter =
  847. m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) {
  848. FunctionScopePtr fs = *iter;
  849. if (fs->isStatic()) fs->setDynamic();
  850. }
  851. if (!m_parent.empty()) {
  852. if (derivesFromRedeclaring() == Derivation::Redeclaring) {
  853. const ClassScopePtrVec &parents = ar->findRedeclaredClasses(m_parent);
  854. for (ClassScopePtr cl: parents) {
  855. cl->setStaticDynamic(ar);
  856. }
  857. } else {
  858. ClassScopePtr parent = ar->findClass(m_parent);
  859. if (parent) {
  860. parent->setStaticDynamic(ar);
  861. }
  862. }
  863. }
  864. }
  865. void ClassScope::setDynamic(AnalysisResultConstPtr ar,
  866. const std::string &name) {
  867. StringToFunctionScopePtrMap::const_iterator iter =
  868. m_functions.find(name);
  869. if (iter != m_functions.end()) {
  870. FunctionScopePtr fs = iter->second;
  871. fs->setDynamic();
  872. } else if (!m_parent.empty()) {
  873. if (derivesFromRedeclaring() == Derivation::Redeclaring) {
  874. const ClassScopePtrVec &parents = ar->findRedeclaredClasses(m_parent);
  875. for (ClassScopePtr cl: parents) {
  876. cl->setDynamic(ar, name);
  877. }
  878. } else {
  879. ClassScopePtr parent = ar->findClass(m_parent);
  880. if (parent) {
  881. parent->setDynamic(ar, name);
  882. }
  883. }
  884. }
  885. }
  886. void ClassScope::setSystem() {
  887. setAttribute(ClassScope::System);
  888. m_volatile = m_dynamic = false;
  889. for (FunctionScopePtrVec::const_iterator iter =
  890. m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) {
  891. (*iter)->setSystem();
  892. }
  893. }
  894. bool ClassScope::needLazyStaticInitializer() {
  895. return getVariables()->getAttribute(VariableTable::ContainsDynamicStatic) ||
  896. getConstants()->hasDynamic();
  897. }
  898. bool ClassScope::hasConst(const string &name) const {
  899. const Symbol *sym = m_constants->getSymbol(name);
  900. assert(!sym || sym->isPresent());
  901. return sym;
  902. }
  903. Symbol *ClassScope::findProperty(ClassScopePtr &cls,
  904. const string &name,
  905. AnalysisResultConstPtr ar) {
  906. return getVariables()->findProperty(cls, name, ar);
  907. }
  908. TypePtr ClassScope::checkProperty(BlockScopeRawPtr context,
  909. Symbol *sym, TypePtr type,
  910. bool coerce, AnalysisResultConstPtr ar) {
  911. return getVariables()->checkProperty(context, sym, type, coerce, ar);
  912. }
  913. TypePtr ClassScope::checkConst(BlockScopeRawPtr context,
  914. const std::string &name, TypePtr type,
  915. bool coerce, AnalysisResultConstPtr ar,
  916. ConstructPtr construct,
  917. const std::vector<std::string> &bases,
  918. BlockScope *&defScope) {
  919. defScope = nullptr;
  920. return getConstants()->check(context, name, type, coerce,
  921. ar, construct, m_bases, defScope);
  922. }
  923. void ClassScope::getInterfaces(AnalysisResultConstPtr ar,
  924. std::vector<std::string> &names,
  925. bool recursive /* = true */) const {
  926. ClassScope *self = const_cast<ClassScope*>(this);
  927. if (recursive && !m_parent.empty()) {
  928. ClassScopePtr cls(ar->findClass(m_parent));
  929. if (cls && cls->isRedeclaring()) {
  930. cls = self->findExactClass(cls);
  931. }
  932. if (cls) cls->getInterfaces(ar, names, true);
  933. }
  934. if (!m_bases.empty()) {
  935. for (auto const& base : m_bases) {
  936. if (base == m_parent) continue;
  937. ClassScopePtr cls(ar->findClass(base));
  938. if (cls && cls->isRedeclaring()) {
  939. cls = self->findExactClass(cls);
  940. }
  941. if (cls && recursive) {
  942. names.push_back(cls ? cls->getDocName() : base);
  943. cls->getInterfaces(ar, names, true);
  944. } else if (std::find_if(names.begin(), names.end(),
  945. [base](std::string& b) {
  946. return string_eqstri()(base,b);
  947. }) == names.end()) {
  948. names.push_back(base);
  949. }
  950. }
  951. }
  952. }
  953. ClassScopePtr ClassScope::getParentScope(AnalysisResultConstPtr ar) const {
  954. if (m_parent.empty()) return ClassScopePtr();
  955. return ar->findClass(m_parent);
  956. }
  957. void ClassScope::serialize(JSON::CodeError::OutputStream &out) const {
  958. JSON::CodeError::MapStream ms(out);
  959. std::map<string, int> propMap;
  960. std::set<string> names;
  961. m_variables->getNames(names);
  962. for (const string& name: names) {
  963. int pm = 0;
  964. if (m_variables->isPublic(name)) pm |= ClassScope::Public;
  965. else if (m_variables->isPrivate(name)) pm |= ClassScope::Private;
  966. else if (m_variables->isProtected(name)) pm |= ClassScope::Protected;
  967. if (m_variables->isStatic(name)) pm |= ClassScope::Static;
  968. propMap[name] = pm;
  969. }
  970. names.clear();
  971. vector<string> cnames;
  972. m_constants->getSymbols(cnames);
  973. // What's a mod again?
  974. ms.add("attributes", m_attribute)
  975. .add("kind", (int) m_kindOf)
  976. .add("parent", m_parent)
  977. .add("bases", m_bases)
  978. .add("properties", propMap)
  979. .add("functions", m_functions);
  980. ms.add("consts");
  981. JSON::CodeError::MapStream cs(out);
  982. for (const string& cname: cnames) {
  983. TypePtr type = m_constants->getType(cname);
  984. if (!type) {
  985. cs.add(cname, -1);
  986. } else if (type->isSpecificObject()) {
  987. cs.add(cname, type->getName());
  988. } else {
  989. cs.add(cname, type->getKindOf());
  990. }
  991. }
  992. cs.done();
  993. ms.done();
  994. }
  995. static inline string GetDocName(AnalysisResultPtr ar,
  996. BlockScopeRawPtr scope,
  997. const string &name) {
  998. ClassScopePtr c(ar->findClass(name));
  999. if (c && c->isRedeclaring()) {
  1000. ClassScopePtr exact(scope->findExactClass(c));
  1001. return exact ?
  1002. exact->getDocName() :
  1003. c->getOriginalName(); // if we can't tell which redec class,
  1004. // then don't use the redec name
  1005. }
  1006. // TODO: pick a better way of signaling unknown?
  1007. return c ? c->getDocName() : "UnknownClass";
  1008. }
  1009. class GetDocNameFunctor {
  1010. public:
  1011. GetDocNameFunctor(AnalysisResultPtr ar, BlockScopeRawPtr scope) :
  1012. m_ar(ar), m_scope(scope) {}
  1013. inline string operator()(const string &name) const {
  1014. return GetDocName(m_ar, m_scope, name);
  1015. }
  1016. private:
  1017. AnalysisResultPtr m_ar;
  1018. BlockScopeRawPtr m_scope;
  1019. };
  1020. void ClassScope::serialize(JSON::DocTarget::OutputStream &out) const {
  1021. // TODO(stephentu): fix this hack
  1022. ClassScopeRawPtr self(const_cast<ClassScope*>(this));
  1023. JSON::DocTarget::MapStream ms(out);
  1024. ms.add("name", getDocName());
  1025. ms.add("line", getStmt() ? getStmt()->getLocation()->line0 : 0);
  1026. ms.add("docs", m_docComment);
  1027. ms.add("parent");
  1028. if (m_parent.empty()) {
  1029. out << JSON::Null();
  1030. } else {
  1031. out << GetDocName(out.analysisResult(), self, m_parent);
  1032. }
  1033. vector<string> ifaces;
  1034. getInterfaces(out.analysisResult(), ifaces, true);
  1035. vector<string> origIfaces;
  1036. origIfaces.resize(ifaces.size());
  1037. transform(ifaces.begin(), ifaces.end(), origIfaces.begin(),
  1038. GetDocNameFunctor(out.analysisResult(), self));
  1039. ms.add("interfaces", origIfaces);
  1040. int mods = 0;
  1041. switch (m_kindOf) {
  1042. case KindOf::AbstractClass: mods |= ClassInfo::IsAbstract; break;
  1043. case KindOf::Enum:
  1044. case KindOf::FinalClass:
  1045. mods |= ClassInfo::IsFinal; break;
  1046. case KindOf::UtilClass:
  1047. mods |= ClassInfo::IsFinal | ClassInfo::IsAbstract; break;
  1048. case KindOf::Interface: mods |= ClassInfo::IsInterface; break;
  1049. case KindOf::Trait: mods |= ClassInfo::IsTrait; break;
  1050. case KindOf::ObjectClass:
  1051. break;
  1052. }
  1053. ms.add("modifiers", mods);
  1054. FunctionScopePtrVec funcs;
  1055. getFunctionsFlattened(0, funcs);
  1056. ms.add("methods", funcs);
  1057. vector<Symbol*> rawSymbols;
  1058. getVariables()->getSymbols(rawSymbols, true);
  1059. vector<SymClassVarWrapper> wrappedSymbols;
  1060. for (vector<Symbol*>::iterator it = rawSymbols.begin();
  1061. it != rawSymbols.end(); ++it) {
  1062. wrappedSymbols.push_back(SymClassVarWrapper(*it));
  1063. }
  1064. ms.add("properties", wrappedSymbols);
  1065. // TODO: constants
  1066. ms.done();
  1067. }
  1068. bool ClassScope::hasProperty(const string &name) const {
  1069. const Symbol *sym = m_variables->getSymbol(name);
  1070. assert(!sym || sym->isPresent());
  1071. return sym;
  1072. }
  1073. void ClassScope::setRedeclaring(AnalysisResultConstPtr ar, int redecId) {
  1074. if (isTrait()) {
  1075. Compiler::Error(Compiler::RedeclaredTrait, m_stmt);
  1076. }
  1077. m_redeclaring = redecId;
  1078. setVolatile(); // redeclared class is also volatile
  1079. for (FunctionScopePtrVec::const_iterator iter =
  1080. m_functionsVec.begin(); iter != m_functionsVec.end(); ++iter) {
  1081. (*iter)->setDynamic();
  1082. }
  1083. }
  1084. bool ClassScope::addFunction(AnalysisResultConstPtr ar,
  1085. FunctionScopePtr funcScope) {
  1086. FunctionScopePtr &func = m_functions[funcScope->getName()];
  1087. if (func) {
  1088. func->getStmt()->parseTimeFatal(Compiler::DeclaredMethodTwice,
  1089. "Redeclared method %s::%s",
  1090. getOriginalName().c_str(),
  1091. func->getOriginalName().c_str());
  1092. }
  1093. func = funcScope;
  1094. m_functionsVec.push_back(funcScope);
  1095. return true;
  1096. }
  1097. bool ClassScope::canSkipCreateMethod(AnalysisResultConstPtr ar) const {
  1098. // create() is not necessary if
  1099. // 1) not inheriting from any class
  1100. // 2) no constructor defined (__construct or class name)
  1101. // 3) no init() defined
  1102. if (derivesFromRedeclaring() == Derivation::Redeclaring ||
  1103. getAttribute(HasConstructor) ||
  1104. getAttribute(ClassNameConstructor) ||
  1105. needsInitMethod()) {
  1106. return false;
  1107. }
  1108. if (!m_parent.empty()) {
  1109. ClassScopePtr parent = getParentScope(ar);
  1110. if (parent) return parent->canSkipCreateMethod(ar);
  1111. }
  1112. return true;
  1113. }