Arquivos
hhvm/hphp/compiler/analysis/class_scope.h
T
ptarjan bc49d78100 tell closures about scope clones
In HHBC mode, traits are flattened into their classes.
When that happens, closures need to know about all the
classes that contain them so that when we find a ##$this##
inside the closure, it can tell EVERY containing scope to
please propogate ##$this## down to me.
2013-03-14 14:27:22 -07:00

493 linhas
17 KiB
C++

/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef __CLASS_SCOPE_H__
#define __CLASS_SCOPE_H__
#include <compiler/analysis/block_scope.h>
#include <compiler/analysis/function_container.h>
#include <compiler/statement/class_statement.h>
#include <compiler/statement/method_statement.h>
#include <compiler/statement/trait_prec_statement.h>
#include <compiler/statement/trait_alias_statement.h>
#include <compiler/expression/user_attribute.h>
#include <util/json.h>
#include <util/case_insensitive.h>
#include <compiler/option.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
DECLARE_BOOST_TYPES(StatementList);
DECLARE_BOOST_TYPES(FunctionScope);
DECLARE_BOOST_TYPES(ClassScope);
DECLARE_BOOST_TYPES(FileScope);
class Symbol;
/**
* A class scope corresponds to a class declaration. We store all
* inferred types and analyzed results here, so not to pollute syntax trees.
*/
class ClassScope : public BlockScope, public FunctionContainer,
public JSON::CodeError::ISerializable,
public JSON::DocTarget::ISerializable {
public:
enum KindOf {
KindOfObjectClass,
KindOfAbstractClass,
KindOfFinalClass,
KindOfInterface,
KindOfTrait
};
#define DECLARE_MAGIC(prefix, prev) \
prefix ## UnknownPropGetter = prev << 1, /* __get */ \
prefix ## UnknownPropSetter = prev << 2, /* __set */ \
prefix ## UnknownPropTester = prev << 3, /* __isset */ \
prefix ## PropUnsetter = prev << 4, /* __unset */ \
prefix ## UnknownMethodHandler = prev << 5, /* __call */ \
prefix ## UnknownStaticMethodHandler = prev << 6, /* __callStatic */ \
prefix ## InvokeMethod = prev << 7, /* __invoke */ \
prefix ## ArrayAccess = prev << 8 /* Implements ArrayAccess */
enum Attribute {
System = 0x001,
Extension = 0x002,
/**
* set iff there is a __construct method. check ClassNameConstructor if
* you want to know whether there is a class-name constructor.
*/
HasConstructor = 0x0004,
ClassNameConstructor = 0x0008,
HasDestructor = 0x0010,
NotFinal = 0x0020,
UsesUnknownTrait = 0x0040,
DECLARE_MAGIC(Has, UsesUnknownTrait),
DECLARE_MAGIC(MayHave, HasArrayAccess),
DECLARE_MAGIC(Inherits, MayHaveArrayAccess)
};
enum Modifier {
Public = 1,
Protected = 2,
Private = 4,
Static = 8,
Abstract = 16,
Final = 32
};
enum Derivation {
FromNormal = 0,
DirectFromRedeclared,
IndirectFromRedeclared
};
enum JumpTableName {
JumpTableCallInfo
};
public:
ClassScope(KindOf kindOf, const std::string &name,
const std::string &parent,
const std::vector<std::string> &bases,
const std::string &docComment, StatementPtr stmt,
const std::vector<UserAttributePtr> &attrs);
/**
* Special constructor for extension classes.
*/
ClassScope(AnalysisResultPtr ar,
const std::string &name, const std::string &parent,
const std::vector<std::string> &bases,
const FunctionScopePtrVec &methods);
bool classNameCtor() const {
return getAttribute(ClassNameConstructor);
}
const std::string &getOriginalName() const;
std::string getDocName() const;
virtual std::string getId() const;
void checkDerivation(AnalysisResultPtr ar, hphp_string_iset &seen);
const std::string &getOriginalParent() const { return m_parent; }
/**
* Returns topmost parent class that has the method.
*/
ClassScopePtr getRootParent(AnalysisResultConstPtr ar,
const std::string &methodName = "");
void getRootParents(AnalysisResultConstPtr ar, const std::string &methodName,
ClassScopePtrVec &roots, ClassScopePtr curClass);
/**
* Whether this is a user-defined class.
*/
bool isUserClass() const { return !getAttribute(System);}
bool isExtensionClass() const { return getAttribute(Extension); }
bool isDynamic() const { return m_dynamic; }
bool isBaseClass() const { return m_bases.empty(); }
/**
* Whether this class name was declared twice or more.
*/
void setRedeclaring(AnalysisResultConstPtr ar, int redecId);
bool isRedeclaring() const { return m_redeclaring >= 0;}
int getRedeclaringId() { return m_redeclaring; }
void setStaticDynamic(AnalysisResultConstPtr ar);
void setDynamic(AnalysisResultConstPtr ar, const std::string &name);
void addReferer(BlockScopePtr ref, int useKinds);
/* For class_exists */
void setVolatile();
bool isVolatile() const { return m_volatile;}
bool isPersistent() const { return m_persistent; }
void setPersistent(bool p) { m_persistent = p; }
bool needLazyStaticInitializer();
Derivation derivesFromRedeclaring() const {
return m_derivesFromRedeclaring;
}
bool derivedByDynamic() const {
return m_derivedByDynamic;
}
/* Whether this class is brought in by a separable extension */
void setSepExtension() { m_sep = true;}
bool isSepExtension() const { return m_sep;}
/**
* Get/set attributes.
*/
void setSystem();
void setAttribute(Attribute attr) { m_attribute |= attr;}
void clearAttribute(Attribute attr) { m_attribute &= ~attr;}
bool getAttribute(Attribute attr) const {
return m_attribute & attr;
}
bool hasAttribute(Attribute attr, AnalysisResultConstPtr ar) const {
if (getAttribute(attr)) return true;
ClassScopePtr parent = getParentScope(ar);
return parent && !parent->isRedeclaring() && parent->hasAttribute(attr, ar);
}
void setKnownBase(int i) { assert(i < 32); m_knownBases |= 1u << i; }
bool hasUnknownBases() const {
int n = m_bases.size();
if (!n) return false;
if (n >= 32) n = 0;
return m_knownBases != (((1u << n) - 1) & 0xffffffff);
}
bool hasKnownBase(int i) const {
return m_knownBases & (1u << (i < 32 ? i : 31));
}
const FunctionScopePtrVec &getFunctionsVec() const {
return m_functionsVec;
}
/**
* Called by ClassScope to prepare name => method/property map.
*/
void collectMethods(AnalysisResultPtr ar,
StringToFunctionScopePtrMap &func,
bool collectPrivate = true,
bool forInvoke = false);
/**
* Whether or not we can directly call ObjectData::o_invoke() when lookup
* in this class fails. If false, we need to call parent::o_invoke(), which
* may be redeclared or may have private methods that need to check class
* context.
*/
bool needsInvokeParent(AnalysisResultConstPtr ar, bool considerSelf = true);
/*
void collectProperties(AnalysisResultPtr ar,
std::set<std::string> &names,
bool collectPrivate = true) const;
*/
/**
* Testing whether this class derives from another.
*/
bool derivesDirectlyFrom(const std::string &base) const;
bool derivesFrom(AnalysisResultConstPtr ar, const std::string &base,
bool strict, bool def) const;
/**
* Find a common parent of two classes; returns "" if there is no such.
*/
static ClassScopePtr FindCommonParent(AnalysisResultConstPtr ar,
const std::string &cn1,
const std::string &cn2);
/**
* Look up function by name.
*/
FunctionScopePtr findFunction(AnalysisResultConstPtr ar,
const std::string &name,
bool recursive,
bool exclIntfBase = false);
/**
* Look up constructor, both __construct and class-name constructor.
*/
FunctionScopePtr findConstructor(AnalysisResultConstPtr ar,
bool recursive);
Symbol *findProperty(ClassScopePtr &cls, const std::string &name,
AnalysisResultConstPtr ar);
/**
* Caller is assumed to hold a lock on this scope
*/
TypePtr checkProperty(BlockScopeRawPtr context,
Symbol *sym, TypePtr type,
bool coerce, AnalysisResultConstPtr ar);
/**
* Caller is *NOT* assumed to hold any locks. Context is
*/
TypePtr checkConst(BlockScopeRawPtr context,
const std::string &name, TypePtr type,
bool coerce, AnalysisResultConstPtr ar,
ConstructPtr construct,
const std::vector<std::string> &bases,
BlockScope *&defScope);
/**
* Collect parent class names.
*/
void getAllParents(AnalysisResultConstPtr ar,
std::vector<std::string> &names);
void getInterfaces(AnalysisResultConstPtr ar,
std::vector<std::string> &names,
bool recursive = true) const;
std::vector<std::string> &getBases() { return m_bases;}
typedef hphp_hash_map<std::string, ExpressionPtr, string_hashi,
string_eqstri> UserAttributeMap;
UserAttributeMap& userAttributes() { return m_userAttributes;}
ClassScopePtr getParentScope(AnalysisResultConstPtr ar) const;
void addUsedTrait(const std::string &s) {
if (!usesTrait(s)) {
m_usedTraitNames.push_back(s);
}
}
void addUsedTraits(const std::vector<std::string> &names) {
for (unsigned i = 0; i < names.size(); i++) {
if (!usesTrait(names[i])) {
m_usedTraitNames.push_back(names[i]);
}
}
}
const std::vector<std::string> &getUsedTraitNames() const {
return m_usedTraitNames;
}
const std::vector<std::pair<std::string, std::string> > &getTraitAliases()
const {
return m_traitAliases;
}
void addTraitAlias(TraitAliasStatementPtr aliasStmt);
void importUsedTraits(AnalysisResultPtr ar);
/**
* Serialize the iface, not everything.
*/
void serialize(JSON::CodeError::OutputStream &out) const;
void serialize(JSON::DocTarget::OutputStream &out) const;
bool isInterface() const { return m_kindOf == KindOfInterface; }
bool isFinal() const { return m_kindOf == KindOfFinalClass ||
m_kindOf == KindOfTrait; }
bool isAbstract() const { return m_kindOf == KindOfAbstractClass ||
m_kindOf == KindOfTrait; }
bool isTrait() const { return m_kindOf == KindOfTrait; }
bool hasProperty(const std::string &name) const;
bool hasConst(const std::string &name) const;
static bool NeedStaticArray(ClassScopePtr cls, FunctionScopePtr func);
void inheritedMagicMethods(ClassScopePtr super);
void derivedMagicMethods(ClassScopePtr super);
/* true if it might, false if it doesnt */
bool implementsArrayAccess();
/* true if it might, false if it doesnt */
bool implementsAccessor(int prop);
void outputForwardDeclaration(CodeGenerator &cg);
void clearBases() {
m_bases.clear();
m_parent = "";
}
/**
* Override function container
*/
bool addFunction(AnalysisResultConstPtr ar,
FunctionScopePtr funcScope);
void setNeedsCppCtor(bool needsCppCtor) {
m_needsCppCtor = needsCppCtor;
}
bool needsCppCtor() const {
return m_needsCppCtor;
}
void setNeedsInitMethod(bool needsInit) {
m_needsInit = needsInit;
}
bool needsInitMethod() const {
return m_needsInit;
}
bool needsEnableDestructor(AnalysisResultConstPtr ar) const;
bool canSkipCreateMethod(AnalysisResultConstPtr ar) const;
bool checkHasPropTable(AnalysisResultConstPtr ar);
private:
// need to maintain declaration order for ClassInfo map
FunctionScopePtrVec m_functionsVec;
std::string m_parent;
mutable std::vector<std::string> m_bases;
UserAttributeMap m_userAttributes;
std::vector<std::string> m_usedTraitNames;
// m_traitAliases is used to support ReflectionClass::getTraitAliases
std::vector<std::pair<std::string, std::string> > m_traitAliases;
struct TraitMethod {
const ClassScopePtr m_trait;
const MethodStatementPtr m_method;
const std::string m_originalName;
ModifierExpressionPtr m_modifiers;
const StatementPtr m_ruleStmt; // for methods imported via aliasing
TraitMethod(ClassScopePtr trait, MethodStatementPtr method,
ModifierExpressionPtr modifiers, StatementPtr ruleStmt) :
m_trait(trait), m_method(method),
m_originalName(method->getOriginalName()), m_modifiers(modifiers),
m_ruleStmt(ruleStmt) {
}
TraitMethod(ClassScopePtr trait, MethodStatementPtr method,
ModifierExpressionPtr modifiers, StatementPtr ruleStmt,
const std::string &originalName) :
m_trait(trait), m_method(method), m_originalName(originalName),
m_modifiers(modifiers), m_ruleStmt(ruleStmt) {
}
};
typedef std::list<TraitMethod> TraitMethodList;
typedef std::map<std::string, TraitMethodList> MethodToTraitListMap;
typedef std::map<std::string, std::string> GeneratorRenameMap;
MethodToTraitListMap m_importMethToTraitMap;
typedef std::map<std::string, MethodStatementPtr> ImportedMethodMap;
mutable int m_attribute;
int m_redeclaring; // multiple definition of the same class
KindOf m_kindOf;
Derivation m_derivesFromRedeclaring;
enum TraitStatus {
NOT_FLATTENED,
BEING_FLATTENED,
FLATTENED
} m_traitStatus;
unsigned m_dynamic:1;
unsigned m_volatile:1; // for class_exists
unsigned m_persistent:1;
unsigned m_derivedByDynamic:1;
unsigned m_sep:1;
unsigned m_needsCppCtor:1;
unsigned m_needsInit:1;
// m_knownBases has a bit for each base class saying whether
// its known to exist at the point of definition of this class.
// for classes with more than 31 bases, bit 31 is set iff
// bases 32 through n are all known.
unsigned m_knownBases;
mutable unsigned m_needsEnableDestructor:2;
void addImportTraitMethod(const TraitMethod &traitMethod,
const std::string &methName);
void informClosuresAboutScopeClone(ConstructPtr root,
FunctionScopePtr outerScope,
AnalysisResultPtr ar);
void setImportTraitMethodModifiers(const std::string &methName,
ClassScopePtr traitCls,
ModifierExpressionPtr modifiers);
MethodStatementPtr importTraitMethod(const TraitMethod& traitMethod,
AnalysisResultPtr ar,
std::string methName,
GeneratorRenameMap& genRenameMap,
const ImportedMethodMap &
importedTraitMethods);
void importTraitProperties(AnalysisResultPtr ar);
void relinkGeneratorMethods(AnalysisResultPtr ar,
ImportedMethodMap& importedMethods);
void findTraitMethodsToImport(AnalysisResultPtr ar, ClassScopePtr trait);
MethodStatementPtr findTraitMethod(AnalysisResultPtr ar,
ClassScopePtr trait,
const std::string &methodName,
std::set<ClassScopePtr> &visitedTraits);
void applyTraitRules(AnalysisResultPtr ar);
void applyTraitPrecRule(TraitPrecStatementPtr stmt);
void applyTraitAliasRule(AnalysisResultPtr ar, TraitAliasStatementPtr stmt);
ClassScopePtr findSingleTraitWithMethod(AnalysisResultPtr ar,
const std::string &methodName) const;
void removeSpareTraitAbstractMethods(AnalysisResultPtr ar);
bool usesTrait(const std::string &traitName) const;
bool hasMethod(const std::string &methodName) const;
const std::string& getNewGeneratorName(FunctionScopePtr genFuncScope,
GeneratorRenameMap& genRenameMap);
void renameCreateContinuationCalls(AnalysisResultPtr ar, ConstructPtr c,
ImportedMethodMap &importedMethods);
};
///////////////////////////////////////////////////////////////////////////////
}
#endif // __CLASS_SCOPE_H__