File: declarationbuilder.h

package info (click to toggle)
kdevelop-php 24.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,616 kB
  • sloc: cpp: 20,858; php: 15,243; xml: 136; sh: 58; makefile: 10
file content (240 lines) | stat: -rw-r--r-- 11,032 bytes parent folder | download
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