Add internal identifier to functions, methods, properties and classes
[hiphop-php.git] / hphp / runtime / vm / preclass.cpp
blob641d64a51c2234a3d742b57c2ef279b8589dcfbe
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/preclass.h"
19 #include "hphp/runtime/base/array-iterator.h"
20 #include "hphp/runtime/base/attr.h"
21 #include "hphp/runtime/base/datatype.h"
22 #include "hphp/runtime/base/repo-auth-type.h"
23 #include "hphp/runtime/base/string-data.h"
24 #include "hphp/runtime/base/typed-value.h"
25 #include "hphp/runtime/vm/func.h"
26 #include "hphp/runtime/vm/hhbc.h"
27 #include "hphp/runtime/vm/unit.h"
29 #include <ostream>
30 #include <sstream>
32 namespace HPHP {
33 ///////////////////////////////////////////////////////////////////////////////
35 PreClass::PreClass(Unit* unit, int line1, int line2, const StringData* n,
36 Attr attrs, const StringData* parent, const StringData* docComment,
37 Id id)
38 : m_unit(unit)
39 , m_namedEntity(NamedEntity::get(n))
40 , m_line1(line1)
41 , m_line2(line2)
42 , m_id(id)
43 , m_attrs(attrs)
44 , m_name(n)
45 , m_parent(parent)
46 , m_docComment(docComment)
50 PreClass::~PreClass() {
51 std::for_each(methods(), methods() + numMethods(), Func::destroy);
54 void PreClass::atomicRelease() {
55 delete this;
58 const StringData* PreClass::manglePropName(const StringData* className,
59 const StringData* propName,
60 Attr attrs) {
61 switch (attrs & VisibilityAttrs) {
62 case AttrPublic: {
63 return propName;
65 case AttrProtected: {
66 std::string mangledName = "";
67 mangledName.push_back('\0');
68 mangledName.push_back('*');
69 mangledName.push_back('\0');
70 mangledName += propName->data();
71 return makeStaticString(mangledName);
73 case AttrPrivate: {
74 std::string mangledName = "";
75 mangledName.push_back('\0');
76 mangledName += className->data();
77 mangledName.push_back('\0');
78 mangledName += propName->data();
79 return makeStaticString(mangledName);
81 default:
82 //Failing here will cause the VM to crash before the Verifier runs, so we
83 //defer the failure to runtime so the Verifier can report this problem to
84 //the user.
85 return staticEmptyString();
89 void PreClass::prettyPrint(std::ostream &out) const {
90 if (m_attrs & AttrSealed) { out << "<<__Sealed()>> "; }
91 out << "Class ";
92 if (m_attrs & AttrAbstract) { out << "abstract "; }
93 if (m_attrs & AttrFinal) { out << "final "; }
94 if (m_attrs & AttrInterface) { out << "interface "; }
95 out << m_name->data();
96 if (m_attrs & AttrNoOverride){ out << " (nooverride)"; }
97 if (m_attrs & AttrUnique) out << " (unique)";
98 if (m_attrs & AttrPersistent) out << " (persistent)";
99 if (m_attrs & AttrIsConst) {
100 // AttrIsConst classes will always also have AttrForbidDynamicProps set,
101 // so don't bother printing it
102 out << " (const)";
103 } else if (m_attrs & AttrForbidDynamicProps) {
104 out << " (no-dynamic-props)";
106 if (m_attrs & AttrDynamicallyConstructible) out << " (dyn_constructible)";
107 if (m_id != -1) {
108 out << " (ID " << m_id << ")";
110 out << std::endl;
112 for (Func* const* it = methods(); it != methods() + numMethods(); ++it) {
113 out << " ";
114 (*it)->prettyPrint(out);
116 for (const Prop* it = properties();
117 it != properties() + numProperties();
118 ++it) {
119 out << " ";
120 it->prettyPrint(out, this);
122 for (const Const* it = constants();
123 it != constants() + numConstants();
124 ++it) {
125 out << " ";
126 it->prettyPrint(out, this);
130 const StaticString s___Sealed("__Sealed");
131 void PreClass::enforceInMaybeSealedParentWhitelist(
132 const PreClass* parentPreClass) const {
133 // if our parent isn't sealed, then we're fine. If we're a mock, YOLO
134 if (!(parentPreClass->attrs() & AttrSealed) ||
135 m_userAttributes.find(s___MockClass.get()) != m_userAttributes.end()) {
136 return;
138 const UserAttributeMap& parent_attrs = parentPreClass->userAttributes();
139 assertx(parent_attrs.find(s___Sealed.get()) != parent_attrs.end());
140 const auto& parent_sealed_attr = parent_attrs.find(s___Sealed.get())->second;
141 bool in_sealed_whitelist = false;
142 IterateV(parent_sealed_attr.m_data.parr,
143 [&in_sealed_whitelist, this](TypedValue v) -> bool {
144 if (v.m_data.pstr->same(name())) {
145 in_sealed_whitelist = true;
146 return true;
148 return false;
150 if (!in_sealed_whitelist) {
151 raise_error("Class %s may not inherit from sealed %s (%s) without "
152 "being in the whitelist",
153 name()->data(),
154 parentPreClass->attrs() & AttrInterface ? "interface" : "class",
155 parentPreClass->name()->data());
159 const StaticString s___EnableMethodTraitDiamond("__EnableMethodTraitDiamond");
160 bool PreClass::enableMethodTraitDiamond() {
161 return m_userAttributes.find(s___EnableMethodTraitDiamond.get()) != m_userAttributes.end();
164 ///////////////////////////////////////////////////////////////////////////////
165 // PreClass::Prop.
167 PreClass::Prop::Prop(PreClass* preClass,
168 const StringData* name,
169 Attr attrs,
170 const StringData* userType,
171 const TypeConstraint& typeConstraint,
172 const CompactVector<TypeConstraint>& ubs,
173 const StringData* docComment,
174 const TypedValue& val,
175 RepoAuthType repoAuthType,
176 UserAttributeMap userAttributes)
177 : m_name(name)
178 , m_mangledName(manglePropName(preClass->name(), name, attrs))
179 , m_attrs(attrs)
180 , m_userType{userType}
181 , m_docComment(docComment)
182 , m_val(val)
183 , m_repoAuthType{repoAuthType}
184 , m_typeConstraint{typeConstraint}
185 , m_userAttributes(userAttributes) {
186 m_ubs.resize(ubs.size());
187 std::copy(ubs.begin(), ubs.end(), m_ubs.begin());
190 void PreClass::Prop::prettyPrint(std::ostream& out,
191 const PreClass* preClass) const {
192 out << "Property ";
193 if (m_attrs & AttrStatic) { out << "static "; }
194 if (m_attrs & AttrPublic) { out << "public "; }
195 if (m_attrs & AttrProtected) { out << "protected "; }
196 if (m_attrs & AttrPrivate) { out << "private "; }
197 if (m_attrs & AttrInternal) { out << "internal "; }
198 if (m_attrs & AttrPersistent) { out << "(persistent) "; }
199 if (m_attrs & AttrIsConst) { out << "(const) "; }
200 if (m_attrs & AttrTrait) { out << "(trait) "; }
201 if (m_attrs & AttrNoBadRedeclare) { out << "(no-bad-redeclare) "; }
202 if (m_attrs & AttrNoOverride) { out << "(no-override) "; }
203 if (m_attrs & AttrSystemInitialValue) { out << "(system-initial-val) "; }
204 if (m_attrs & AttrNoImplicitNullable) { out << "(no-implicit-nullable) "; }
205 if (m_attrs & AttrInitialSatisfiesTC) { out << "(initial-satisfies-tc) "; }
206 if (m_attrs & AttrLSB) { out << "(lsb) "; }
207 if (m_attrs & AttrLateInit) { out << "(late-init) "; }
208 out << preClass->name()->data() << "::" << m_name->data() << " = ";
209 if (m_val.m_type == KindOfUninit) {
210 out << "<non-scalar>";
211 } else {
212 std::string ss;
213 staticStreamer(&m_val, ss);
214 out << ss;
216 out << " (RAT = " << show(m_repoAuthType) << ")";
217 if (m_userType && !m_userType->empty()) {
218 out << " (user-type = " << m_userType->data() << ")";
220 if (m_typeConstraint.hasConstraint()) {
221 out << " (tc = " << m_typeConstraint.displayName(nullptr, true) << ")";
223 if (!m_ubs.empty()) {
224 out << "(ubs = ";
225 for (auto const& ub : m_ubs) {
226 if (ub.hasConstraint()) {
227 out << ub.displayName(nullptr, true);
228 out << " ";
231 out << ")";
233 out << std::endl;
236 ///////////////////////////////////////////////////////////////////////////////
237 // PreClass::Const.
239 PreClass::Const::Const(const StringData* name,
240 const StringData* cls,
241 const TypedValueAux& val,
242 Array resolvedTypeStructure,
243 Invariance invariance,
244 bool fromTrait)
245 : m_name(name)
246 , m_cls(cls)
247 , m_val(val)
248 , m_resolvedTypeStructure(std::move(resolvedTypeStructure))
249 , m_invariance(invariance)
250 , m_fromTrait(fromTrait)
253 void PreClass::Const::prettyPrint(std::ostream& out,
254 const PreClass* preClass) const {
255 switch (kind()) {
256 case ConstModifiers::Kind::Value:
257 break;
258 case ConstModifiers::Kind::Type:
259 out << "Type ";
260 break;
261 case ConstModifiers::Kind::Context:
262 out << "Context ";
263 break;
265 auto const name = [&] {
266 out << preClass->name()->data() << "::" << m_name->data();
267 if (cls()) out << " (" << cls()->data() << ")";
269 if (isAbstractAndUninit()) {
270 out << "Constant (abstract) ";
271 name();
272 out << std::endl;
273 return;
275 if (kind() == ConstModifiers::Kind::Context) {
276 out << "Constant ";
277 name();
278 out << " " << coeffects().toString()
279 << std::endl;
280 return;
282 out << "Constant ";
283 name();
284 if (m_val.m_type == KindOfUninit) {
285 out << " = <non-scalar>";
286 } else {
287 std::string ss;
288 staticStreamer(&m_val, ss);
289 out << " = " << ss;
291 if (!m_resolvedTypeStructure.isNull()) {
292 std::string ss;
293 auto const tv =
294 make_array_like_tv(m_resolvedTypeStructure.get());
295 staticStreamer(&tv, ss);
296 out << " (resolved = " << ss << ")";
297 switch (invariance()) {
298 case Invariance::None:
299 break;
300 case Invariance::Present:
301 out << " <present>";
302 break;
303 case Invariance::ClassnamePresent:
304 out << " <classname>";
305 break;
306 case Invariance::Same:
307 out << " <same>";
308 break;
311 out << std::endl;
314 StaticCoeffects PreClass::Const::coeffects() const {
315 assertx(kind() == ConstModifiers::Kind::Context);
316 return m_val.constModifiers().getCoeffects();
319 ///////////////////////////////////////////////////////////////////////////////
320 // PreClass::TraitAliasRule.
322 PreClass::TraitAliasRule::NamePair
323 PreClass::TraitAliasRule::asNamePair() const {
324 auto const tmp = folly::sformat(
325 "{}::{}",
326 traitName()->empty() ? "(null)" : traitName()->data(),
327 origMethodName());
329 auto origName = makeStaticString(tmp);
330 return std::make_pair(newMethodName(), origName);
333 ///////////////////////////////////////////////////////////////////////////////