File: abstractdeclarationbuilder.h

package info (click to toggle)
kdevelop 4%3A24.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 71,888 kB
  • sloc: cpp: 290,869; python: 3,626; javascript: 3,518; sh: 1,316; ansic: 703; xml: 401; php: 95; lisp: 66; makefile: 31; sed: 12
file content (231 lines) | stat: -rw-r--r-- 10,203 bytes parent folder | download | duplicates (2)
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
/*
    SPDX-FileCopyrightText: 2006-2008 Hamish Rodda <rodda@kde.org>

    SPDX-License-Identifier: LGPL-2.0-only
*/

#ifndef KDEVPLATFORM_ABSTRACTDECLARATIONBUILDER_H
#define KDEVPLATFORM_ABSTRACTDECLARATIONBUILDER_H

#include <typeinfo>

#include "../classfunctiondeclaration.h"
#include "../forwarddeclaration.h"
#include "../types/identifiedtype.h"
#include "../functiondeclaration.h"

namespace KDevelop {
class Declaration;

/**
 * A class which iterates the AST to extract definitions of types.
 */
template <typename T, typename NameT, typename LanguageSpecificDeclarationBuilderBase>
class AbstractDeclarationBuilder
    : public LanguageSpecificDeclarationBuilderBase
{
protected:
    /// Determine if there is currently a declaration open. \returns true if a declaration is open, otherwise false.
    inline bool hasCurrentDeclaration() const { return !m_declarationStack.isEmpty(); }
    /// Access the current declaration. \returns the current declaration, or null if there is no current declaration.
    inline Declaration* currentDeclaration() const
    {
        return m_declarationStack.isEmpty() ? nullptr : m_declarationStack.top();
    }
    /// Access the current declaration, casted to type \a DeclarationType. \returns the current declaration if one exists and is an instance of the given \a DeclarationType.
    template <class DeclarationType>
    inline DeclarationType* currentDeclaration() const
    {
        return m_declarationStack.isEmpty() ? nullptr : dynamic_cast<DeclarationType*>(m_declarationStack.top());
    }

    /// Access the current comment. \returns the current comment, or an empty string if none exists.
    inline const QByteArray& comment() const { return m_lastComment; }
    /// Set the current \a comment. \param comment the new comment.
    inline void setComment(const QByteArray& comment) { m_lastComment = comment; }
    /// Clears the current comment.
    inline void clearComment() { m_lastComment.clear(); }

    enum DeclarationFlags {
        NoFlags    = 0x0,
        DeclarationIsDefinition = 0x1
    };

    /**
     * Register a new declaration with the definition-use chain
     * \param name When this is zero, the identifier given through customName is used
     * \param range provide a valid AST node here if name is null
     * \param flags equal to <b>DeclarationIsDefinition</b> whether the new declaration is also a definition
     * \return the new declaration created
     */
    template <class DeclarationT>
    DeclarationT* openDeclaration(NameT* name, T* range, DeclarationFlags flags = NoFlags)
    {
        DUChainWriteLocker lock(DUChain::lock());

        RangeInRevision newRange = this->editorFindRange(name ? name : range, name ? name : range);

        QualifiedIdentifier id = this->identifierForNode(name);

        return openDeclaration<DeclarationT>(id, newRange, flags);
    }

    /**
     * \brief \copybrief openDeclaration(NameT*,T*,DeclarationFlags)
     *
     * \param id the identifier of the new declaration.
     * \param newRange the range which the identifier for the new declaration occupies.
     * \param flags equal to <b>DeclarationIsDefinition</b> whether the new declaration is also a definition
     * \return the new declaration created
     */
    template <class DeclarationT>
    Q_DECL_DEPRECATED_X("Use openDeclaration(Identifier) instead")
    DeclarationT * openDeclaration(const QualifiedIdentifier &id, const RangeInRevision &newRange,
                                   DeclarationFlags flags = NoFlags)
    {
        if (id.count() > 1) {
            qWarning() << "openDeclaration called with a multi-component QualifiedIdentifier!";
        }
        Identifier localId;

        if (!id.isEmpty()) {
            localId = id.last();
        }

        return openDeclaration<DeclarationT>(localId, newRange, flags);
    }
    /**
     * \brief \copybrief openDeclaration(NameT*,T*,DeclarationFlags)
     *
     * \param localId the identifier of the new declaration.
     * \param newRange the range which the identifier for the new declaration occupies.
     * \param flags equal to <b>DeclarationIsDefinition</b> whether the new declaration is also a definition
     * \return the new declaration created
     */
    template <class DeclarationT>
    DeclarationT* openDeclaration(const Identifier& localId, const RangeInRevision& newRange,
                                  DeclarationFlags flags = NoFlags)
    {
        DeclarationT* declaration = nullptr;

        if (LanguageSpecificDeclarationBuilderBase::recompiling()) {
            // Seek a matching declaration

            const QList<Declaration*> declarations =
                LanguageSpecificDeclarationBuilderBase::currentContext()->findLocalDeclarations(localId,
                                                                                                CursorInRevision::invalid(),
                                                                                                this->topContext(),
                                                                                                AbstractType::Ptr(),
                                                                                                DUContext::NoFiltering);
            for (Declaration* dec : declarations) {
                if (LanguageSpecificDeclarationBuilderBase::wasEncountered(dec))
                    continue;

                if (dec->range() == newRange &&
                    (localId == dec->identifier() || (localId.isUnique() && dec->identifier().isUnique())) &&
                    typeid(*dec) == typeid(DeclarationT)
                    //&& extraDeclarationComparisons()
                ) {
                    // Match
                    declaration = dynamic_cast<DeclarationT*>(dec);
                    break;
                }
            }
        }

        if (!declaration) {
            declaration = new DeclarationT(newRange, LanguageSpecificDeclarationBuilderBase::currentContext());

            if (flags & DeclarationIsDefinition)
                declaration->setDeclarationIsDefinition(true);
            declaration->setIdentifier(localId);
        }

        declaration->setComment(m_lastComment);
        m_lastComment.clear();

        LanguageSpecificDeclarationBuilderBase::setEncountered(declaration);

        openDeclarationInternal(declaration);

        return declaration;
    }

    /// Convenience function. Same as openDeclaration(), but creates the declaration as a definition.
    template <class DeclarationT>
    DeclarationT* openDefinition(NameT* name, T* range)
    {
        return openDeclaration<DeclarationT>(name, range, DeclarationIsDefinition);
    }

    /// Convenience function. Same as openDeclaration(), but creates the declaration as a definition.
    template <class DeclarationT>
    DeclarationT* openDefinition(const QualifiedIdentifier& id, const RangeInRevision& newRange)
    {
        return openDeclaration<DeclarationT>(id, newRange, DeclarationIsDefinition);
    }

    /// Internal function to open the given \a declaration by pushing it onto the declaration stack.
    /// Provided for subclasses who don't want to use the generic openDeclaration() functions.
    void openDeclarationInternal(Declaration* declaration)
    {
        m_declarationStack.push(declaration);
    }

    /// Convenience function. Same as openDeclaration(), but creates a forward declaration.
    ForwardDeclaration* openForwardDeclaration(NameT* name, T* range)
    {
        return openDeclaration<ForwardDeclaration>(name, range);
    }

    /// Set the internal context of a declaration; for example, a class declaration's internal context
    /// is the context inside the brackets: class ClassName { ... }
    void eventuallyAssignInternalContext()
    {
        if (LanguageSpecificDeclarationBuilderBase::lastContext()) {
            DUChainWriteLocker lock(DUChain::lock());

            if (dynamic_cast<ClassFunctionDeclaration*>(currentDeclaration()))
                Q_ASSERT(
                    !static_cast<ClassFunctionDeclaration*>(currentDeclaration())->isConstructor() ||
                    currentDeclaration()->context()->type() == DUContext::Class);

            if (LanguageSpecificDeclarationBuilderBase::lastContext() &&
                (LanguageSpecificDeclarationBuilderBase::lastContext()->type() == DUContext::Class ||
                 LanguageSpecificDeclarationBuilderBase::lastContext()->type() == DUContext::Other ||
                 LanguageSpecificDeclarationBuilderBase::lastContext()->type() == DUContext::Function ||
                 LanguageSpecificDeclarationBuilderBase::lastContext()->type() == DUContext::Template ||
                 LanguageSpecificDeclarationBuilderBase::lastContext()->type() == DUContext::Enum ||
                 (LanguageSpecificDeclarationBuilderBase::lastContext()->type() == DUContext::Namespace &&
                  currentDeclaration()->kind() == Declaration::Namespace)
                )) {
                if (!LanguageSpecificDeclarationBuilderBase::lastContext()->owner() ||
                    !LanguageSpecificDeclarationBuilderBase::wasEncountered(LanguageSpecificDeclarationBuilderBase::
                                                                            lastContext()->owner())) {                                                                                                     //if the context is already internalContext of another declaration, leave it alone
                    currentDeclaration()->setInternalContext(LanguageSpecificDeclarationBuilderBase::lastContext());

                    LanguageSpecificDeclarationBuilderBase::clearLastContext();
                }
            }
        }
    }

    /// Close a declaration. Virtual to allow subclasses to perform customisations to declarations.
    virtual void closeDeclaration()
    {
        m_declarationStack.pop();
    }

    /// Abort a declaration, deleting it.
    void abortDeclaration()
    {
        delete m_declarationStack.pop();
    }

private:
    Stack<Declaration*> m_declarationStack;
    QByteArray m_lastComment;
};
}

#endif // KDEVPLATFORM_ABSTRACTDECLARATIONBUILDER_H