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