2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_CONSTRUCT_H_
18 #define incl_HPHP_CONSTRUCT_H_
20 #include "hphp/compiler/json.h"
21 #include "hphp/compiler/code_generator.h"
22 #include "hphp/compiler/analysis/code_error.h"
23 #include "hphp/compiler/analysis/block_scope.h"
26 ///////////////////////////////////////////////////////////////////////////////
29 DECLARE_BOOST_TYPES(StatementList
);
30 DECLARE_BOOST_TYPES(IParseHandler
);
31 DECLARE_BOOST_TYPES(Location
);
32 DECLARE_BOOST_TYPES(AnalysisResult
);
33 DECLARE_BOOST_TYPES(BlockScope
);
34 DECLARE_BOOST_TYPES(ClassScope
);
35 DECLARE_BOOST_TYPES(FunctionScope
);
36 DECLARE_BOOST_TYPES(FileScope
);
38 class AstWalkerStateVec
;
42 * To avoid iteration of parse tree, we move any work that can be done
43 * in parse phase into this function, so to speed up static analysis.
46 virtual ~IParseHandler() {}
49 * onParse is called by the parser when the construct has just been parsed
50 * to allow it to do any necessary work
52 virtual void onParse(AnalysisResultConstPtr ar
, FileScopePtr scope
) {
56 * onParseRecur is called by a parent construct (ultimately a class or
58 * This is done because at the time that onParse would be called for
59 * (eg) a method, the ClassScope doesnt exist. So we wait until onParse
60 * is called for the class, and it calls onParseRecur for its children.
62 virtual void onParseRecur(AnalysisResultConstPtr ar
, ClassScopePtr scope
) {
68 * Base class of Expression and Statement.
70 class Construct
: public std::enable_shared_from_this
<Construct
>,
71 public JSON::CodeError::ISerializable
{
73 Construct(BlockScopePtr scope
, LocationPtr loc
);
75 virtual ~Construct() {}
79 IOEffect
= 1, // could have an observable effect (not
80 // changing variable values)
81 AssignEffect
= 2, // writes an object in a way understood by the
83 GlobalEffect
= 4, // could affect global variables
84 LocalEffect
= 8, // could affect variables from the local scope
85 ParamEffect
= 0x10, // a function could affect its parameters
86 DeepParamEffect
= 0x20, // a function could affect the array elements
87 // or object members referenced by its
89 DynamicParamEffect
= 0x40, // a function creates dynamic exps based
90 // on its parameters, which it could affect
91 CanThrow
= 0x80, // can throw PHP exception
92 AccessorEffect
= 0x100, // could contain a getter/setter
93 CreateEffect
= 0x200, // could cause the creation of an array
94 // element or an object property
95 DiagnosticEffect
= 0x400, // can cause a diagnostic to be issued
96 OtherEffect
= 0x800, // something else
97 UnknownEffect
= 0xfff // any of the above
100 LocationPtr
getLocation() const { return m_loc
;}
101 void setLocation(LocationPtr loc
) { m_loc
= loc
;}
102 void setFileLevel() { m_flags
.topLevel
= m_flags
.fileLevel
= true;}
103 void setTopLevel() { m_flags
.topLevel
= true;}
104 void setVisited() { m_flags
.visited
= true;}
105 void clearVisited() { m_flags
.visited
= false;}
106 bool isFileLevel() const { return m_flags
.fileLevel
;}
107 bool isTopLevel() const { return m_flags
.topLevel
;}
108 bool isVisited() const { return m_flags
.visited
; }
110 void setAnticipated() { m_flags
.anticipated
= true; }
111 void clearAnticipated() { m_flags
.anticipated
= false; }
112 bool isAnticipated() const { return m_flags
.anticipated
; }
114 void setAvailable() { m_flags
.available
= true; }
115 void clearAvailable() { m_flags
.available
= false; }
116 bool isAvailable() const { return m_flags
.available
; }
118 void setNonNull() { m_flags
.nonNull
= true; }
119 void clearNonNull() { m_flags
.nonNull
= false; }
120 bool isNonNull() const { return m_flags
.nonNull
; }
122 void setLocalExprAltered() { m_flags
.localExprNotAltered
= false; }
123 void clearLocalExprAltered() { m_flags
.localExprNotAltered
= true; }
124 bool isLocalExprAltered() const { return !m_flags
.localExprNotAltered
; }
125 void setChainRoot() { m_flags
.chainRoot
= true; }
126 void clearChainRoot() { m_flags
.chainRoot
= false; }
127 bool isChainRoot() const { return m_flags
.chainRoot
; }
129 void setReferencedValid() { m_flags
.referenced_valid
= true; }
130 void clearReferencedValid() { m_flags
.referenced_valid
= false; }
131 bool isReferencedValid() const { return m_flags
.referenced_valid
; }
133 void setReferenced() { m_flags
.referenced
= true; }
134 void clearReferenced() { m_flags
.referenced
= false; }
135 bool isReferenced() const { return m_flags
.referenced
; }
137 void setNeededValid() { m_flags
.needed_valid
= true; }
138 void clearNeededValid() { m_flags
.needed_valid
= false; }
139 bool isNeededValid() const { return m_flags
.needed_valid
; }
141 void setNeeded() { m_flags
.needed
= true; }
142 void clearNeeded() { m_flags
.needed
= false; }
143 bool isNeeded() const { return m_flags
.needed
; }
145 void setNoRemove() { m_flags
.noRemove
= true; }
146 void clearNoRemove() { m_flags
.noRemove
= false; }
147 bool isNoRemove() const { return m_flags
.noRemove
; }
149 void setGuarded() { m_flags
.guarded
= true; }
150 void clearGuarded() { m_flags
.guarded
= false; }
151 bool isGuarded() const { return m_flags
.guarded
; }
153 void setRefCounted() { m_flags
.refCounted
= 3; }
154 void clearRefCounted() { m_flags
.refCounted
= 2; }
155 bool maybeRefCounted() const {
156 return !(m_flags
.refCounted
& 2) || (m_flags
.refCounted
& 1);
159 void setInited() { m_flags
.inited
= 3; }
160 void clearInited() { m_flags
.inited
= 2; }
161 bool maybeInited() const {
162 return !(m_flags
.inited
& 2) || (m_flags
.inited
& 1);
165 void setKilled() { m_flags
.killed
= true; }
166 void clearKilled() { m_flags
.killed
= false; }
167 bool isKilled() const { return m_flags
.killed
; }
169 BlockScopeRawPtr
getScope() const { return m_blockScope
; }
170 void setBlockScope(BlockScopeRawPtr scope
) { m_blockScope
= scope
; }
171 FileScopeRawPtr
getFileScope() const {
172 return m_blockScope
->getContainingFile();
174 FunctionScopeRawPtr
getFunctionScope() const {
175 return m_blockScope
->getContainingFunction();
177 ClassScopeRawPtr
getClassScope() const {
178 return m_blockScope
->getContainingClass();
180 void resetScope(BlockScopeRawPtr scope
, bool resetOrigScope
=false);
181 void parseTimeFatal(Compiler::ErrorType error
, const char *fmt
, ...)
182 ATTRIBUTE_PRINTF(3,4);
183 void analysisTimeFatal(Compiler::ErrorType error
, const char *fmt
, ...)
184 ATTRIBUTE_PRINTF(3,4);
185 virtual int getLocalEffects() const { return UnknownEffect
;}
186 int getChildrenEffects() const;
187 int getContainedEffects() const;
188 bool hasEffect() const { return getContainedEffects() != NoEffect
;}
189 virtual bool kidUnused(int i
) const { return false; }
192 static std::shared_ptr
<T
> Clone(std::shared_ptr
<T
> constr
) {
194 return dynamic_pointer_cast
<T
>(constr
->clone());
196 return std::shared_ptr
<T
>();
200 std::shared_ptr
<T
> Clone(std::shared_ptr
<T
> constr
,
201 BlockScopePtr scope
) {
203 constr
= constr
->clone();
204 constr
->resetScope(scope
);
210 * Called when we analyze a program, which file it includes, which function
211 * and class it uses, etc.
213 virtual void analyzeProgram(AnalysisResultPtr ar
) = 0;
216 * return the nth child construct
218 virtual ConstructPtr
getNthKid(int n
) const { return ConstructPtr(); }
221 * set the nth child construct
223 virtual void setNthKid(int n
, ConstructPtr cp
) {}
228 virtual int getKidCount() const = 0;
231 void dump(int spc
, AnalysisResultPtr ar
) {
232 AnalysisResultConstPtr
arp(ar
);
235 void dumpNode(int spc
, AnalysisResultPtr ar
) {
236 AnalysisResultConstPtr
arp(ar
);
239 void dumpNode(int spc
);
240 void dumpNode(int spc
) const;
242 void dump(int spc
, AnalysisResultConstPtr ar
);
243 void dumpNode(int spc
, AnalysisResultConstPtr ar
);
245 static void dump(int spc
, AnalysisResultConstPtr ar
, bool functionOnly
,
246 const AstWalkerStateVec
&start
,
247 ConstructPtr endBefore
, ConstructPtr endAfter
);
250 * Generates a serialized Code Model corresponding to this AST.
252 virtual void outputCodeModel(CodeGenerator
&cg
) = 0;
255 * Called when generating code.
257 virtual void outputPHP(CodeGenerator
&cg
, AnalysisResultPtr ar
) = 0;
260 * Implements JSON::CodeError::ISerializable.
262 virtual void serialize(JSON::CodeError::OutputStream
&out
) const;
265 * Get canonicalized PHP source code for this construct.
267 std::string
getText(bool useCache
, bool translate
= false,
268 AnalysisResultPtr ar
= AnalysisResultPtr());
270 std::string
getText() { return getText(false); }
271 void recomputeEffects();
274 * Write where this construct was in PHP files.
276 void printSource(CodeGenerator
&cg
);
277 ExpressionPtr
makeConstant(AnalysisResultConstPtr ar
,
278 const std::string
&value
) const;
279 ExpressionPtr
makeScalarExpression(AnalysisResultConstPtr ar
,
280 const Variant
&value
) const;
283 BlockScopeRawPtr m_blockScope
;
287 unsigned fileLevel
: 1; // is it at top level of a file
288 unsigned topLevel
: 1; // is it at top level of a scope
289 unsigned visited
: 1; // general purpose for walks
290 unsigned anticipated
: 1;
291 unsigned available
: 1;
292 unsigned localExprNotAltered
: 1; // whether this node can be
293 // altered in this expression
294 unsigned nonNull
: 1; // expression is not null
295 unsigned referenced
: 1;
296 unsigned referenced_valid
: 1; // is the above flag is valid
298 unsigned needed_valid
: 1; // is the above flag is valid
299 unsigned chainRoot
: 1; // is this the begining of a
301 unsigned noRemove
: 1; // DCE should NOT remove this node
302 unsigned guarded
: 1; // previously used
304 unsigned refCounted
: 2; // high bit indicates whether its valid
305 unsigned inited
: 2; // high bit indicates whether its valid
310 mutable int m_containedEffects
;
311 mutable int m_effectsTag
;
314 * Called by analyzeProgram() to add a reference to a user class or
317 void addUserFunction(AnalysisResultPtr ar
, const std::string
&name
);
318 void addUserClass(AnalysisResultPtr ar
, const std::string
&name
);
321 class LocalEffectsContainer
{
323 int getLocalEffects() const { return m_localEffects
; }
324 virtual void effectsCallback() = 0;
326 explicit LocalEffectsContainer(Construct::Effect localEffect
) :
327 m_localEffects(localEffect
) {}
328 LocalEffectsContainer() :
330 void setLocalEffect (Construct::Effect effect
);
331 void clearLocalEffect(Construct::Effect effect
);
332 bool hasLocalEffect (Construct::Effect effect
) const;
337 #define DECL_AND_IMPL_LOCAL_EFFECTS_METHODS \
338 virtual int getLocalEffects() const { \
339 return LocalEffectsContainer::getLocalEffects(); \
341 virtual void effectsCallback() { recomputeEffects(); }
343 ///////////////////////////////////////////////////////////////////////////////
345 #endif // incl_HPHP_CONSTRUCT_H_