1 /*
2     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
3 
4     SPDX-License-Identifier: LGPL-2.0-only
5 */
6 
7 #ifndef KDEVPLATFORM_DECLARATION_ID_H
8 #define KDEVPLATFORM_DECLARATION_ID_H
9 
10 #include "indexeddeclaration.h"
11 #include "identifier.h"
12 #include "instantiationinformation.h"
13 #include <language/util/kdevhash.h>
14 
15 //krazy:excludeall=dpointer
16 
17 namespace KDevelop {
18 class Declaration;
19 class TopDUContext;
20 
21 /**
22  * \short Allows clearly identifying a Declaration.
23  *
24  * DeclarationId is needed to uniquely address Declarations that are in another top-context,
25  * because there may be multiple parsed versions of a file.
26  *
27  * There are two forms of DeclarationId, one indirect and one direct.  The direct form
28  * holds a reference to the Declaration instance, whereas the indirect form stores the qualified
29  * identifier and an additional index to disambiguate instances of multiple declarations with the same
30  * identifier.
31  *
32  * Both forms also have a specialization index. It can be used in a language-specific way to pick other
33  * versions of the declaration. When the declaration is found, Declaration::specialize() is called on
34  * the found declaration with this value, and the returned value is the actually found declaration.
35  *
36  * \note This only works when the Declaration is in the symbol table.
37  * */
38 class KDEVPLATFORMLANGUAGE_EXPORT DeclarationId
39 {
40 public:
41     /**
42      * Constructor for indirect access to a declaration.  The resulting DeclarationId will not
43      * have a direct reference to the Declaration, but will look it up as needed.
44      *
45      * \param id Identifier for this declaration id.
46      * \param additionalId Additional index to disambiguate
47      * \param specialization Specialization index (see class documentation).
48      */
49     explicit DeclarationId(const IndexedQualifiedIdentifier& id = IndexedQualifiedIdentifier(),
50                            uint additionalId = 0,
51                            const IndexedInstantiationInformation& specialization = IndexedInstantiationInformation());
52 
53     /**
54      * Constructor for direct access to a declaration.  The resulting DeclarationId will
55      * directly reference the Declaration
56      *
57      * \param decl Declaration to reference.
58      * \param specialization Specialization index (see class documentation).
59      */
60     explicit DeclarationId(const IndexedDeclaration& decl,
61                            const IndexedInstantiationInformation& specialization = IndexedInstantiationInformation());
62 
63     DeclarationId(const DeclarationId& rhs);
64 
65     ~DeclarationId();
66 
67     DeclarationId& operator=(const DeclarationId& rhs);
68 
69     /**
70      * Equality operator.
71      *
72      * \param rhs declaration identifier to compare.
73      * \returns true if equal, otherwise false.
74      */
75     bool operator==(const DeclarationId& rhs) const
76     {
77         if (m_isDirect != rhs.m_isDirect)
78             return false;
79 
80         if (!m_isDirect)
81             return m_indirectData.identifier == rhs.m_indirectData.identifier
82                    && m_indirectData.additionalIdentity == rhs.m_indirectData.additionalIdentity
83                    && m_specialization == rhs.m_specialization;
84         else
85             return m_directData == rhs.m_directData && m_specialization == rhs.m_specialization;
86     }
87 
88     /**
89      * Not equal operator.
90      *
91      * \param rhs declaration identifier to compare.
92      * \returns true if not equal, otherwise false.
93      */
94     bool operator!=(const DeclarationId& rhs) const
95     {
96         return !operator==(rhs);
97     }
98 
99     /**
100      * Determine whether this declaration identifier references a valid declaration.
101      */
isValid()102     bool isValid() const
103     {
104         return (m_isDirect && m_directData.isValid()) || m_indirectData.identifier.isValid();
105     }
106 
107     /**
108      * Hash function for this declaration identifier.
109      *
110      * \warning This may return different hashes for the same declaration,
111      *          depending on whether the id is direct or indirect,
112      *          and thus you cannot compare hashes for declaration equality (use operator==() instead)
113      */
hash()114     uint hash() const
115     {
116         if (m_isDirect)
117             return KDevHash() << m_directData.hash() << m_specialization.index();
118         else
119             return KDevHash() << m_indirectData.identifier.index() << m_indirectData.additionalIdentity <<
120                    m_specialization.index();
121     }
122 
123     /**
124      * Retrieve the declaration, from the perspective of \a context.
125      * In order to be retrievable, the declaration must be in the symbol table.
126      *
127      * \param context Context in which to search for the Declaration.
128      * \param instantiateIfRequired Whether the declaration should be instantiated if required
129      * \returns the referenced Declaration, or null if none was found.
130      * */
131     Declaration* declaration(const TopDUContext* context, bool instantiateIfRequired = true) const;
132 
133     /**
134      * Same as declaration(..), but returns all matching declarations if there are multiple.
135      * This also returns found forward-declarations.
136      */
137     KDevVarLengthArray<Declaration*> declarations(const TopDUContext* context) const;
138 
139     /**
140      * Set the specialization index (see class documentation).
141      *
142      * \param spec the new specialization index.
143      */
144     void setSpecialization(const IndexedInstantiationInformation& spec);
145 
146     /**
147      * Retrieve the specialization index (see class documentation).
148      *
149      * \returns the specialization index.
150      */
151     IndexedInstantiationInformation specialization() const;
152 
153     /**
154      * Determine whether this DeclarationId directly references a Declaration by indices,
155      * or if it uses identifiers and other data to reference the Declaration.
156      *
157      * \returns true if direct, false if indirect.
158      */
159     bool isDirect() const;
160 
161     /**
162      * Return the qualified identifier for this declaration.
163      *
164      * \warning This is relatively expensive, and not 100% correct in all cases(actually a top-context would be needed to resolve this correctly),
165      *          so avoid using this, except for debugging purposes.
166      */
167     QualifiedIdentifier qualifiedIdentifier() const;
168 
169 private:
170     /// An indirect reference to the declaration, which uses the symbol-table for lookup. Should be preferred for all
171     /// declarations that are in the symbol-table
172     struct Indirect
173     {
174         IndexedQualifiedIdentifier identifier;
175         /// Hash from signature, or similar. Used to disambiguate multiple declarations of the same name.
176         uint additionalIdentity;
177 
178         Indirect& operator=(const Indirect& rhs) = default;
179     };
180 
181     union {
182         Indirect m_indirectData;
183         IndexedDeclaration m_directData;
184     };
185     bool m_isDirect;
186 
187     // Can be used in a language-specific way to pick other versions of the declaration.
188     // When the declaration is found, pickSpecialization is called on the found declaration
189     // with this value, and the returned value is the actually found declaration.
190     IndexedInstantiationInformation m_specialization;
191 };
192 
qHash(const KDevelop::DeclarationId & id)193 inline uint qHash(const KDevelop::DeclarationId& id)
194 {
195     return id.hash();
196 }
197 }
198 
199 Q_DECLARE_TYPEINFO(KDevelop::DeclarationId, Q_MOVABLE_TYPE);
200 
201 #endif
202