998951619f
We did not intend to imply our copyrights last forever Closes #759
491 linhas
17 KiB
C++
491 linhas
17 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 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 incl_HPHP_CLASS_SCOPE_H_
|
|
#define incl_HPHP_CLASS_SCOPE_H_
|
|
|
|
#include "hphp/compiler/analysis/block_scope.h"
|
|
#include "hphp/compiler/analysis/function_container.h"
|
|
#include "hphp/compiler/statement/class_statement.h"
|
|
#include "hphp/compiler/statement/method_statement.h"
|
|
#include "hphp/compiler/statement/trait_prec_statement.h"
|
|
#include "hphp/compiler/statement/trait_alias_statement.h"
|
|
#include "hphp/compiler/expression/user_attribute.h"
|
|
#include "hphp/util/json.h"
|
|
#include "hphp/util/case_insensitive.h"
|
|
#include "hphp/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 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;
|
|
|
|
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 // incl_HPHP_CLASS_SCOPE_H_
|