2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 +----------------------------------------------------------------------+
16 #include "hphp/hhbbc/class-util.h"
18 #include "hphp/hhbbc/analyze.h"
19 #include "hphp/hhbbc/context.h"
20 #include "hphp/hhbbc/index.h"
21 #include "hphp/hhbbc/representation.h"
22 #include "hphp/hhbbc/type-system.h"
24 #include "hphp/runtime/base/array-init.h"
25 #include "hphp/runtime/base/collections.h"
27 #include "hphp/runtime/vm/preclass-emitter.h"
29 #include <boost/algorithm/string/predicate.hpp>
31 namespace HPHP::HHBBC
{
33 //////////////////////////////////////////////////////////////////////
38 s_SimpleXMLElement("SimpleXMLElement"),
40 s_MockClass("__MockClass"),
41 s_NoFlatten("__NoFlatten"),
43 s_debugInfo("__debugInfo"),
44 s_construct("__construct");
48 //////////////////////////////////////////////////////////////////////
50 bool has_magic_bool_conversion(SString clsName
) {
52 collections::isTypeName(clsName
) ||
53 clsName
->tsame(s_SimpleXMLElement
.get());
56 bool is_collection(res::Class cls
) {
57 auto const name
= cls
.name();
58 return collections::isTypeName(name
);
61 php::Func
* find_method(const php::Class
* cls
, SString name
) {
62 for (auto& m
: cls
->methods
) {
63 if (m
->name
== name
) {
70 bool is_special_method_name(SString name
) {
71 auto const p
= name
->data();
72 return p
&& p
[0] == '8' && p
[1] == '6';
75 bool has_name_only_func_family(SString name
) {
77 name
!= s_construct
.get() &&
78 name
!= s_invoke
.get() &&
79 name
!= s_debugInfo
.get() &&
80 !is_special_method_name(name
);
83 bool is_mock_class(const php::Class
* cls
) {
84 return cls
->userAttributes
.count(s_MockClass
.get());
87 bool is_noflatten_trait(const php::Class
* cls
) {
88 assertx(cls
->attrs
& AttrTrait
);
89 return cls
->userAttributes
.count(s_NoFlatten
.get());
92 bool is_closure_base(SString name
) {
93 return name
->tsame(s_Closure
.get());
96 bool is_closure_base(const php::Class
& c
) {
97 return c
.name
->tsame(s_Closure
.get());
100 bool is_closure(const php::Class
& c
) {
101 return c
.parentName
&& c
.parentName
->tsame(s_Closure
.get());
104 bool is_closure_name(SString name
) {
105 return boost::starts_with(name
->slice(), "Closure$");
108 bool is_unused_trait(const php::Class
& c
) {
110 (c
.attrs
& (AttrTrait
| AttrNoOverride
)) == (AttrTrait
| AttrNoOverride
);
113 bool is_used_trait(const php::Class
& c
) {
115 (c
.attrs
& (AttrTrait
| AttrNoOverride
)) == AttrTrait
;
118 //////////////////////////////////////////////////////////////////////
120 Type
get_type_of_reified_list(const UserAttributeMap
& ua
) {
121 auto const it
= ua
.find(s___Reified
.get());
122 assertx(it
!= ua
.end());
123 auto const tv
= it
->second
;
124 assertx(tvIsVec(&tv
));
125 auto const info
= extractSizeAndPosFromReifiedAttribute(tv
.m_data
.parr
);
126 auto const numGenerics
= info
.m_typeParamInfo
.size();
127 assertx(numGenerics
> 0);
129 auto t
= vec(std::vector
<Type
>(numGenerics
, TDict
));
131 // If the type params are all soft, the reified list is allowed to
133 auto const allSoft
= [&] {
134 for (auto const& tp
: info
.m_typeParamInfo
) {
135 if (!tp
.m_isSoft
) return false;
139 if (allSoft
) t
|= TVecE
;
143 // The value returned from this must satisfy the type returned from
144 // get_type_of_reified_list.
145 TypedValue
get_default_value_of_reified_list(const UserAttributeMap
& ua
) {
146 auto const it
= ua
.find(s___Reified
.get());
147 assertx(it
!= ua
.end());
148 auto const tv
= it
->second
;
149 assertx(tvIsVec(&tv
));
150 auto const info
= extractSizeAndPosFromReifiedAttribute(tv
.m_data
.parr
);
151 auto const numGenerics
= info
.m_typeParamInfo
.size();
152 assertx(numGenerics
> 0);
154 // Empty vec is allowed for the "all soft" case, so use that if it
156 auto const allSoft
= [&] {
157 for (auto const& tp
: info
.m_typeParamInfo
) {
158 if (!tp
.m_isSoft
) return false;
162 if (allSoft
) return make_tv
<KindOfPersistentVec
>(staticEmptyVec());
164 // Otherwise make a vec of the appropriate size filled with empty
165 // dicts, which satisfies get_type_of_reified_list.
166 VecInit init
{numGenerics
};
167 for (size_t i
= 0; i
< numGenerics
; ++i
) {
168 init
.append(make_tv
<KindOfPersistentDict
>(staticEmptyDictArray()));
170 auto var
= init
.toVariant();
172 return *var
.asTypedValue();
175 Type
loosen_this_prop_for_serialization(const php::Class
& ctx
,
178 // The 86reified_prop has special enforcement for serialization, so
179 // we don't have to pessimize it as much.
180 if (name
== s_86reified_prop
.get()) {
183 get_type_of_reified_list(ctx
.userAttributes
)
186 return loosen_vec_or_dict(loosen_all(std::move(type
)));
189 //////////////////////////////////////////////////////////////////////
193 //////////////////////////////////////////////////////////////////////
195 ClassBase::ClassBase(const ClassBase
& other
) {
196 for (auto& m
: other
.methods
) {
198 methods
.emplace_back();
200 methods
.emplace_back(std::make_unique
<php::Func
>(*m
));
203 for (auto& c
: other
.closures
) {
204 closures
.emplace_back(std::make_unique
<php::Class
>(*c
));
208 //////////////////////////////////////////////////////////////////////
212 //////////////////////////////////////////////////////////////////////