2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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 +----------------------------------------------------------------------+
17 #include "hphp/compiler/expression/static_member_expression.h"
18 #include "hphp/compiler/expression/simple_variable.h"
19 #include "hphp/compiler/expression/dynamic_variable.h"
20 #include "hphp/compiler/expression/scalar_expression.h"
21 #include "hphp/compiler/analysis/class_scope.h"
22 #include "hphp/compiler/analysis/variable_table.h"
23 #include "hphp/compiler/analysis/code_error.h"
24 #include "hphp/compiler/analysis/function_scope.h"
25 #include "hphp/util/util.h"
26 #include "hphp/util/hash.h"
27 #include "hphp/parser/hphp.tab.hpp"
28 #include "hphp/compiler/option.h"
32 ///////////////////////////////////////////////////////////////////////////////
33 // constructors/destructors
35 StaticMemberExpression::StaticMemberExpression
36 (EXPRESSION_CONSTRUCTOR_PARAMETERS
,
37 ExpressionPtr classExp
, ExpressionPtr exp
)
38 : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(StaticMemberExpression
)),
39 StaticClassName(classExp
), m_exp(exp
), m_valid(false),
40 m_dynamicClass(false) {
41 if (exp
->is(KindOfSimpleVariable
)) {
42 SimpleVariablePtr
s(dynamic_pointer_cast
<SimpleVariable
>(exp
));
44 (new ScalarExpression(getScope(), getLocation(),
45 T_STRING
, s
->getName(), true));
48 always_assert(exp
->is(KindOfDynamicVariable
));
49 m_exp
= dynamic_pointer_cast
<DynamicVariable
>(exp
)->getSubExpression();
53 ExpressionPtr
StaticMemberExpression::clone() {
54 StaticMemberExpressionPtr
exp(new StaticMemberExpression(*this));
55 Expression::deepCopy(exp
);
56 if (m_class
) exp
->m_class
= m_class
->clone();
57 exp
->m_exp
= m_exp
->clone();
61 ///////////////////////////////////////////////////////////////////////////////
64 ///////////////////////////////////////////////////////////////////////////////
65 // static analysis functions
67 bool StaticMemberExpression::findMember(AnalysisResultPtr ar
, string
&name
,
69 if (m_exp
->is(Expression::KindOfScalarExpression
)) {
70 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(m_exp
);
71 name
= var
->getString();
74 if (m_class
) return false;
77 m_resolvedClass
= resolveClass();
78 if (!m_resolvedClass
) return isRedeclared();
80 if (m_resolvedClass
->derivesFromRedeclaring() == Derivation::Redeclaring
) {
81 m_dynamicClass
= true;
84 if (m_dynamicClass
) return true;
87 ClassScopePtr parent
= m_resolvedClass
;
88 sym
= m_resolvedClass
->findProperty(parent
, name
, ar
);
89 if (sym
&& sym
->isStatic()) {
90 m_resolvedClass
= parent
;
99 void StaticMemberExpression::analyzeProgram(AnalysisResultPtr ar
) {
101 m_class
->analyzeProgram(ar
);
102 } else if (ar
->getPhase() >= AnalysisResult::AnalyzeAll
) {
105 if (findMember(ar
, name
, sym
)) {
106 if (m_resolvedClass
) {
107 m_resolvedClass
->addUse(getScope(), BlockScope::UseKindStaticRef
);
108 if (!sym
&& !m_dynamicClass
&& !name
.empty() &&
109 ar
->getPhase() == AnalysisResult::AnalyzeFinal
&&
110 !m_resolvedClass
->isTrait()) {
111 Compiler::Error(Compiler::UseUndeclaredVariable
, shared_from_this());
115 addUserClass(ar
, m_className
);
117 m_exp
->analyzeProgram(ar
);
120 ConstructPtr
StaticMemberExpression::getNthKid(int n
) const {
130 return ConstructPtr();
133 int StaticMemberExpression::getKidCount() const {
137 void StaticMemberExpression::setNthKid(int n
, ConstructPtr cp
) {
140 m_class
= dynamic_pointer_cast
<Expression
>(cp
);
143 m_exp
= dynamic_pointer_cast
<Expression
>(cp
);
151 ExpressionPtr
StaticMemberExpression::preOptimize(AnalysisResultConstPtr ar
) {
152 if (m_class
) updateClassName();
153 return ExpressionPtr();
156 ExpressionPtr
StaticMemberExpression::postOptimize(AnalysisResultConstPtr ar
) {
157 Symbol
*sym
= nullptr;
158 if (m_class
) updateClassName();
159 if (m_class
|| !m_resolvedClass
|| !m_valid
||
160 !m_exp
->is(Expression::KindOfScalarExpression
)) {
161 return ExpressionPtr();
164 ClassScopePtr cls
= ar
->findExactClass(shared_from_this(), m_className
);
165 if (!cls
|| (cls
->isVolatile() && !isPresent())) {
166 return ExpressionPtr();
169 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(m_exp
);
170 const std::string
&name
= var
->getString();
172 sym
= cls
->findProperty(cls
, name
, ar
);
173 if (sym
&& !sym
->isIndirectAltered() && sym
->isStatic()) {
174 if (sym
->isPrivate() ? cls
== getClassScope() :
176 getClassScope() && getClassScope()->derivesFrom(ar
, cls
->getName(),
179 ConstructPtr init
= sym
->getClassInitVal();
181 ExpressionPtr rep
= dynamic_pointer_cast
<Expression
>(init
);
182 if (rep
->isScalar()) {
183 ExpressionPtr repClone
= Clone(rep
, getScope());
184 if (!repClone
->getActualType()) {
185 repClone
->setActualType(getActualType());
187 return replaceValue(repClone
);
192 return ExpressionPtr();
196 * static_member can only be one of these two forms:
199 * T::$$member or T::${$member}, where $member can be an arbitrary expression
200 * The former is represented by a ScalarExpression with value "member",
201 * the latter by the expression $member.
203 TypePtr
StaticMemberExpression::inferTypes(AnalysisResultPtr ar
,
204 TypePtr type
, bool coerce
) {
205 assert(getScope()->is(BlockScope::FunctionScope
));
206 ConstructPtr self
= shared_from_this();
208 bool modified
= m_context
& (LValue
| RefValue
| UnsetContext
| RefParameter
);
209 if (m_context
& (RefValue
|RefParameter
)) {
211 type
= Type::Variant
;
215 if (m_exp
->is(Expression::KindOfScalarExpression
)) {
216 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(m_exp
);
217 const std::string
&name
= var
->getString();
218 ar
->forceClassVariants(name
, getOriginalClass(), true, true);
220 ar
->forceClassVariants(getOriginalClass(), true, true);
223 m_class
->inferAndCheck(ar
, Type::Any
, false);
224 m_exp
->inferAndCheck(ar
, Type::String
, false);
225 return Type::Variant
;
228 m_exp
->inferAndCheck(ar
, Type::String
, false);
233 m_valid
= findMember(ar
, name
, sym
);
235 if (getScope()->isFirstPass()) {
236 ClassScopeRawPtr cscope
= getClassScope();
238 !cscope
->isTrait() ||
239 (!isSelf() && !isParent())) {
240 Compiler::Error(Compiler::UnknownClass
, self
);
243 } else if (m_resolvedClass
) {
244 m_resolvedClass
->addUse(getScope(), BlockScope::UseKindStaticRef
);
247 VariableTablePtr variables
= getScope()->getVariables();
248 variables
->setAttribute(VariableTable::NeedGlobalPointer
);
251 if (!m_resolvedClass
&& !isRedeclared()) {
252 m_implementedType
.reset();
253 return Type::Variant
;
257 if (isRedeclared()) {
258 BOOST_FOREACH(ClassScopePtr clsr
,
259 ar
->findRedeclaredClasses(m_className
)) {
260 sym
= clsr
->findProperty(clsr
, name
, ar
);
261 if (sym
&& sym
->isStatic()) {
265 sym
->setType(ar
, getScope(), Type::Variant
, true);
266 sym
->setIndirectAltered();
268 clsr
->checkProperty(getScope(), sym
, type
, coerce
, ar
);
277 assert(m_resolvedClass
);
279 GET_LOCK(m_resolvedClass
);
280 tp
= m_resolvedClass
->checkProperty(getScope(), sym
, type
, coerce
, ar
);
284 // concurrent modifications here are OK because:
285 // 1) you never clear the bit (you only set it to true)
286 // 2) the value isn't read in type inference
287 sym
->setIndirectAltered();
290 GET_LOCK(m_resolvedClass
);
291 m_resolvedClass
->getVariables()->
292 forceVariant(ar
, name
,
293 m_resolvedClass
== getOriginalClass() ?
294 VariableTable::AnyStaticVars
:
295 VariableTable::NonPrivateStaticVars
);
298 m_valid
= found
|| isRedeclared() || m_dynamicClass
;
299 m_implementedType
.reset();
303 if (m_resolvedClass
|| isRedeclared()) {
305 if (isRedeclared()) {
306 BOOST_FOREACH(ClassScopePtr clsr
,
307 ar
->findRedeclaredClasses(m_className
)) {
308 int mask
= clsr
== getOriginalClass() ?
309 VariableTable::AnyStaticVars
: VariableTable::NonPrivateStaticVars
;
311 clsr
->getVariables()->forceVariants(ar
, mask
);
314 int mask
= m_resolvedClass
== getOriginalClass() ?
315 VariableTable::AnyStaticVars
: VariableTable::NonPrivateStaticVars
;
316 GET_LOCK(m_resolvedClass
);
317 m_resolvedClass
->getVariables()->forceVariants(ar
, mask
);
322 // we have to use a variant to hold dynamic value
323 m_implementedType
.reset();
324 return Type::Variant
;
327 unsigned StaticMemberExpression::getCanonHash() const {
328 int64_t val
= Expression::getCanonHash() +
329 hash_string(Util::toLower(m_className
).c_str(), m_className
.size());
330 return ~unsigned(val
) ^ unsigned(val
>> 32);
333 bool StaticMemberExpression::canonCompare(ExpressionPtr e
) const {
334 if (!Expression::canonCompare(e
)) return false;
335 StaticMemberExpressionPtr s
=
336 static_pointer_cast
<StaticMemberExpression
>(e
);
337 return m_className
== s
->m_className
;
340 ///////////////////////////////////////////////////////////////////////////////
342 void StaticMemberExpression::outputCodeModel(CodeGenerator
&cg
) {
343 cg
.printObjectHeader("ClassPropertyExpression", 3);
344 StaticClassName::outputCodeModel(cg
);
345 if (m_exp
->is(Expression::KindOfScalarExpression
)) {
346 cg
.printPropertyHeader("propertyName");
347 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(m_exp
);
348 cg
.printValue(var
->getString());
350 cg
.printPropertyHeader("propertyExpression");
351 m_exp
->outputCodeModel(cg
);
353 cg
.printPropertyHeader("sourceLocation");
354 cg
.printLocation(this->getLocation());
355 cg
.printObjectFooter();
358 ///////////////////////////////////////////////////////////////////////////////
359 // code generation functions
361 void StaticMemberExpression::outputPHP(CodeGenerator
&cg
,
362 AnalysisResultPtr ar
) {
363 StaticClassName::outputPHP(cg
, ar
);
366 bool needsClose
= false;
367 switch (m_exp
->getKindOf()) {
368 case KindOfScalarExpression
:
370 ScalarExpressionPtr var
= dynamic_pointer_cast
<ScalarExpression
>(m_exp
);
371 cg_printf("%s", var
->getString().c_str());
374 case KindOfSimpleVariable
:
375 case KindOfDynamicVariable
:
381 m_exp
->outputPHP(cg
, ar
);