1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
|
/*
SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef DECLARATIONBUILDER_H
#define DECLARATIONBUILDER_H
#include "typebuilder.h"
#include "helper.h"
#include <language/duchain/classdeclaration.h>
#include <language/duchain/builders/abstractdeclarationbuilder.h>
namespace KDvelop
{
class Declaration;
}
namespace Php
{
class ParseSession;
class EditorIntegrator;
class ClassDeclaration;
class FunctionDeclaration;
class NamespaceDeclaration;
typedef KDevelop::AbstractDeclarationBuilder<AstNode, IdentifierAst, TypeBuilder> DeclarationBuilderBase;
/**
* The DeclarationBuilder builds declarations, types and contexts for everything in a AST.
*
* \note Since PHP allows the usage of functions, classes and interfaces before definition,
* a \see PreDeclarationBuilder is used to get the declarations _and_ types for those.
* Thus type- and declaratoinbuilding for these is skipped in this class.
*/
class KDEVPHPDUCHAIN_EXPORT DeclarationBuilder : public DeclarationBuilderBase
{
public:
DeclarationBuilder(EditorIntegrator* editor)
: m_currentModifers(0)
{
m_editor = editor;
m_findVariable.find = false;
m_useNamespaceType = ClassDeclarationType;
}
KDevelop::ReferencedTopDUContext build(const KDevelop::IndexedString& url, AstNode* node,
const KDevelop::ReferencedTopDUContext& updateContext
= KDevelop::ReferencedTopDUContext()) override;
void startVisiting(AstNode* node) override;
protected:
void visitClassDeclarationStatement(ClassDeclarationStatementAst *node) override;
void visitInterfaceDeclarationStatement(InterfaceDeclarationStatementAst *node) override;
void visitTraitDeclarationStatement(TraitDeclarationStatementAst *node) override;
void visitClassStatement(ClassStatementAst *node) override;
virtual void importTraitMethods(ClassStatementAst *node);
void visitClassExtends(ClassExtendsAst *node) override;
void visitClassImplements(ClassImplementsAst *node) override;
void visitParameterList(ParameterListAst *node) override;
void visitParameter(ParameterAst *node) override;
void visitFunctionDeclarationStatement(FunctionDeclarationStatementAst *node) override;
void visitGenericTypeHint(GenericTypeHintAst *node) override;
void visitClassVariable(ClassVariableAst *node) override;
void visitConstantDeclaration(ConstantDeclarationAst *node) override;
void visitClassConstantDeclaration(ClassConstantDeclarationAst *node) override;
void visitTraitAliasStatement(TraitAliasStatementAst *node) override;
virtual void createTraitAliasDeclarations(TraitAliasStatementAst *node, KDevelop::DeclarationPointer dec);
void visitOuterTopStatement(OuterTopStatementAst* node) override;
void visitAssignmentExpression(AssignmentExpressionAst* node) override;
void visitAssignmentExpressionEqual(AssignmentExpressionEqualAst *node) override;
void visitVariable(VariableAst* node) override;
void visitFunctionCall(FunctionCallAst* node) override;
void visitFunctionCallParameterList(FunctionCallParameterListAst* node) override;
void visitFunctionCallParameterListElement(FunctionCallParameterListElementAst* node) override;
void visitStatement(StatementAst* node) override;
void visitStaticVar(StaticVarAst* node) override;
void visitGlobalVar(GlobalVarAst* node) override;
void visitCatchItem(CatchItemAst *node) override;
void visitUnaryExpression( UnaryExpressionAst* node ) override;
void visitAssignmentListElement(AssignmentListElementAst* node) override;
void openNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier, const KDevelop::RangeInRevision& range) override;
void closeNamespace(NamespaceDeclarationStatementAst* parent, IdentifierAst* node, const IdentifierPair& identifier) override;
void visitUseStatement(UseStatementAst* node) override;
void visitUseNamespaceOrUseGroupedNamespace(UseNamespaceOrUseGroupedNamespaceAst* node) override;
void visitNonGroupedUseNamespace(UseNamespaceOrUseGroupedNamespaceAst* node);
void visitClosure(ClosureAst* node) override;
void visitLexicalVar(LexicalVarAst* node) override;
void visitVarExpression(VarExpressionAst* node) override;
/// checks whether the body is empty (i.e. equals ";" instead of "{...}")
bool isEmptyMethodBody(const MethodBodyAst* body) const {
return !body || !body->statements;
}
void closeDeclaration() override;
void classContextOpened(KDevelop::DUContext* context) override;
void supportBuild(AstNode* node, KDevelop::DUContext* context = nullptr) override;
void closeContext() override;
/// don't forget to closeDeclaration() afterwards
/// set m_currentModifers to your likings and reset it afterwards
void openClassMemberDeclaration(AstNode* node, const KDevelop::QualifiedIdentifier& name);
void updateCurrentType() override;
private:
/// because the predeclarationbuilder runs before us,
/// we always "think" that we are recompiling, while this is not necessarily true
bool m_actuallyRecompiling;
struct FindVariableResults {
/// Set this to true if you want to catch any variable in the lower AST tree
bool find;
/// If the found variable is accessed as an array ($var[...]) this is set to true.
/// @see m_findVariable
bool isArray;
/// The identifier for the found variable.
/// @see m_findVariable
KDevelop::QualifiedIdentifier identifier;
/// The identifier for the parent of the found variable. Empty if
/// the found variable is not a class member.
/// @see m_findVariable
KDevelop::QualifiedIdentifier parentIdentifier;
/// The AstNode of the found variable. Use this for declarations.
/// @see m_findVariable
AstNode* node;
FindVariableResults();
};
FindVariableResults m_findVariable;
/// The position of the current argument, will only be set inside function calls.
int m_functionCallParameterPos;
/// Type of the current function, will only be set inside function calls.
KDevelop::FunctionType::Ptr m_currentFunctionType;
/// The AstNode of the previous function declaration argument
ParameterAst *m_functionDeclarationPreviousArgument = nullptr;
/// The AstNode of the previous function call argument
FunctionCallParameterListElementAst *m_functionCallPreviousArgument = nullptr;
/// Type of use
DeclarationType m_useNamespaceType;
unsigned int m_currentModifers;
QString m_lastTopStatementComment;
QHash<qint64, ClassDeclaration*> m_types;
QHash<qint64, FunctionDeclaration*> m_functions;
QHash<qint64, NamespaceDeclaration*> m_namespaces;
QVector<KDevelop::QualifiedIdentifier> m_upcomingClassVariables;
/// handles common stuff for both interfaces and classes
ClassDeclaration* openTypeDeclaration(IdentifierAst *name, KDevelop::ClassDeclarationData::ClassType type);
/// check if this declaration is already declared
bool isGlobalRedeclaration(const KDevelop::QualifiedIdentifier &identifier, AstNode *node,
DeclarationType type);
/// check if a non-abstract method declaration tries to overwrite a final base method
/// or whether a abstract method is redeclared
/// @param ids The identifier for the current method
/// @param curClass the current class we are in
/// @param node the node we are processing, used to access modifiers and for error reporting
bool isBaseMethodRedeclaration(const IdentifierPair &ids, ClassDeclaration *curClass,
ClassStatementAst *node);
/// reports a redeclaration error for the given node
/// @param declaration the old declaration
/// @param node the AstNode which resembles the redeclaration
void reportRedeclarationError(KDevelop::Declaration* declaration, AstNode *node);
/**
* Get the interesting identifiers out of a VariableAst node:
* $var yields @p id = 'var', @p parent = ''
* $var->asdf yields @p id = 'asdf', @p parent = 'asdf'
* $var->...->foo->bar yields @p id = 'bar', @p parent => 'foo'
*
* @note If the parent or the identifier itself end on an array access, e.g. $var[0] or
* $var->...->parent[0]->bar, @p arrayAccess will be set to true.
*
* @param id the last identifier
* @param parent the parent of the last identifier
* @param targetNode the node of the last identifier
* @param arrayAccess the node actually ends on an array access, like $node->var->..->asdf[0]
*/
void getVariableIdentifier(VariableAst *node,
KDevelop::QualifiedIdentifier &id,
KDevelop::QualifiedIdentifier &parent,
AstNode* &targetNode,
bool &arrayAccess);
/**
* Declare a class member in @p parentCtx. Validates whether the current context allows
* redeclaration of private/protected members.
*
* @param parentCtx The class context you want to add the member to.
* @param type The type of the member.
* @param identifier The identifier of the member.
* @param node The node of the member.
*/
void declareClassMember(KDevelop::DUContext *parentCtx, KDevelop::AbstractType::Ptr type,
const KDevelop::QualifiedIdentifier& identifier, AstNode* node );
/**
* Declare a variable in @p parentCtx. If the variable is already defined in the
* context and it's last type equals @p type, don't do anything.
*
* @param parentCtx The context you want to declare the variable in.
* @param type The type of the variable
* @param identifier The identifier for the variable.
* @param node The node for the variable.
*/
void declareVariable(KDevelop::DUContext *parentCtx, KDevelop::AbstractType::Ptr type,
const KDevelop::QualifiedIdentifier& identifier, AstNode* node );
/**
* Wrapper that operates declares the found variable. It will declare it
* either as a class member or as a variable, depending whether a parent was found.
*
* It will also check whether that var also exists and if so, won't do anything.
*
* @param type When the var gets declared, this will be it's type.
*
* @see m_findVariable
* @see declareClassMeember
* @see declareVariable
*/
void declareFoundVariable(KDevelop::AbstractType::Ptr type);
/**
* Sets encountered and updates the comment when we are recompiling.
*/
void encounter(KDevelop::Declaration* dec);
bool isReservedClassName(QString className);
};
}
#endif // DECLARATIONBUILDER_H
|