codemod 2010-2016 to 2010-present
[hiphop-php.git] / hphp / runtime / base / data-walker.cpp
blob0b18200bba3485a955b8edfa2f704a474249310f
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 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/data-walker.h"
18 #include "hphp/runtime/base/array-data.h"
19 #include "hphp/runtime/base/object-data.h"
20 #include "hphp/runtime/base/type-variant.h"
21 #include "hphp/runtime/base/array-iterator.h"
22 #include "hphp/runtime/base/collections.h"
24 namespace HPHP {
26 //////////////////////////////////////////////////////////////////////
28 void DataWalker::traverseData(ArrayData* data,
29 DataFeature& features,
30 PointerSet& visited) const {
31 for (ArrayIter iter(data); iter; ++iter) {
32 const Variant& var = iter.secondRef();
34 if (var.isReferenced()) {
35 Variant *pvar = var.getRefData();
36 if (markVisited(pvar, features, visited)) {
37 if (canStopWalk(features)) return;
38 continue; // don't recurse forever; we already went down this path
40 // Right now consider it circular even if the referenced variant only
41 // showed up in one spot. This could be revisted later.
42 features.isCircular = true;
43 if (canStopWalk(features)) return;
46 auto const type = var.getType();
47 // cheap enough, do it always
48 features.hasRefCountReference = isRefcountedType(type);
49 if (type == KindOfObject) {
50 features.hasObjectOrResource = true;
51 traverseData(var.getObjectData(), features, visited);
52 } else if (isArrayLikeType(type)) {
53 traverseData(var.getArrayData(), features, visited);
54 } else if (type == KindOfResource) {
55 features.hasObjectOrResource = true;
57 if (canStopWalk(features)) return;
61 void DataWalker::traverseData(
62 ObjectData* data,
63 DataFeature& features,
64 PointerSet& visited) const {
65 objectFeature(data, features, visited);
66 if (markVisited(data, features, visited)) {
67 return; // avoid infinite recursion
69 if (!canStopWalk(features)) {
70 traverseData(data->toArray().get(), features, visited);
74 inline bool DataWalker::markVisited(
75 void* pvar,
76 DataFeature& features,
77 PointerSet& visited) const {
78 if (!visited.insert(pvar).second) {
79 features.isCircular = true;
80 return true;
82 return false;
85 inline void DataWalker::objectFeature(
86 ObjectData* pobj,
87 DataFeature& features,
88 PointerSet& visited) const {
89 if (pobj->isCollection()) return;
90 if ((m_features & LookupFeature::DetectSerializable) &&
91 pobj->instanceof(SystemLib::s_SerializableClass)) {
92 features.hasSerializable = true;
96 inline bool DataWalker::canStopWalk(DataFeature& features) const {
97 auto refCountCheck =
98 features.hasRefCountReference ||
99 !(m_features & LookupFeature::RefCountedReference);
100 auto objectCheck =
101 features.hasObjectOrResource ||
102 !(m_features & LookupFeature::HasObjectOrResource);
103 auto defaultChecks = features.isCircular || features.hasSerializable;
104 return refCountCheck && objectCheck && defaultChecks;
107 //////////////////////////////////////////////////////////////////////