File: | clang/lib/AST/QualTypeNames.cpp |
Warning: | line 195, column 9 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===------- QualTypeNames.cpp - Generate Complete QualType Names ---------===// | ||||
2 | // | ||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
6 | // | ||||
7 | //===----------------------------------------------------------------------===// | ||||
8 | |||||
9 | #include "clang/AST/DeclTemplate.h" | ||||
10 | #include "clang/AST/DeclarationName.h" | ||||
11 | #include "clang/AST/GlobalDecl.h" | ||||
12 | #include "clang/AST/Mangle.h" | ||||
13 | #include "clang/AST/QualTypeNames.h" | ||||
14 | |||||
15 | #include <stdio.h> | ||||
16 | #include <memory> | ||||
17 | |||||
18 | namespace clang { | ||||
19 | |||||
20 | namespace TypeName { | ||||
21 | |||||
22 | /// Create a NestedNameSpecifier for Namesp and its enclosing | ||||
23 | /// scopes. | ||||
24 | /// | ||||
25 | /// \param[in] Ctx - the AST Context to be used. | ||||
26 | /// \param[in] Namesp - the NamespaceDecl for which a NestedNameSpecifier | ||||
27 | /// is requested. | ||||
28 | /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace | ||||
29 | /// specifier "::" should be prepended or not. | ||||
30 | static NestedNameSpecifier *createNestedNameSpecifier( | ||||
31 | const ASTContext &Ctx, | ||||
32 | const NamespaceDecl *Namesp, | ||||
33 | bool WithGlobalNsPrefix); | ||||
34 | |||||
35 | /// Create a NestedNameSpecifier for TagDecl and its enclosing | ||||
36 | /// scopes. | ||||
37 | /// | ||||
38 | /// \param[in] Ctx - the AST Context to be used. | ||||
39 | /// \param[in] TD - the TagDecl for which a NestedNameSpecifier is | ||||
40 | /// requested. | ||||
41 | /// \param[in] FullyQualify - Convert all template arguments into fully | ||||
42 | /// qualified names. | ||||
43 | /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace | ||||
44 | /// specifier "::" should be prepended or not. | ||||
45 | static NestedNameSpecifier *createNestedNameSpecifier( | ||||
46 | const ASTContext &Ctx, const TypeDecl *TD, | ||||
47 | bool FullyQualify, bool WithGlobalNsPrefix); | ||||
48 | |||||
49 | static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( | ||||
50 | const ASTContext &Ctx, const Decl *decl, | ||||
51 | bool FullyQualified, bool WithGlobalNsPrefix); | ||||
52 | |||||
53 | static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( | ||||
54 | const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); | ||||
55 | |||||
56 | static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, | ||||
57 | TemplateName &TName, | ||||
58 | bool WithGlobalNsPrefix) { | ||||
59 | bool Changed = false; | ||||
60 | NestedNameSpecifier *NNS = nullptr; | ||||
61 | |||||
62 | TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); | ||||
63 | // ArgTDecl won't be NULL because we asserted that this isn't a | ||||
64 | // dependent context very early in the call chain. | ||||
65 | assert(ArgTDecl != nullptr)((ArgTDecl != nullptr) ? static_cast<void> (0) : __assert_fail ("ArgTDecl != nullptr", "/build/llvm-toolchain-snapshot-10~+20191227100609+c3dbd782f1e/clang/lib/AST/QualTypeNames.cpp" , 65, __PRETTY_FUNCTION__)); | ||||
66 | QualifiedTemplateName *QTName = TName.getAsQualifiedTemplateName(); | ||||
67 | |||||
68 | if (QTName && !QTName->hasTemplateKeyword()) { | ||||
69 | NNS = QTName->getQualifier(); | ||||
70 | NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( | ||||
71 | Ctx, NNS, WithGlobalNsPrefix); | ||||
72 | if (QNNS != NNS) { | ||||
73 | Changed = true; | ||||
74 | NNS = QNNS; | ||||
75 | } else { | ||||
76 | NNS = nullptr; | ||||
77 | } | ||||
78 | } else { | ||||
79 | NNS = createNestedNameSpecifierForScopeOf( | ||||
80 | Ctx, ArgTDecl, true, WithGlobalNsPrefix); | ||||
81 | } | ||||
82 | if (NNS) { | ||||
83 | TName = Ctx.getQualifiedTemplateName(NNS, | ||||
84 | /*TemplateKeyword=*/false, ArgTDecl); | ||||
85 | Changed = true; | ||||
86 | } | ||||
87 | return Changed; | ||||
88 | } | ||||
89 | |||||
90 | static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, | ||||
91 | TemplateArgument &Arg, | ||||
92 | bool WithGlobalNsPrefix) { | ||||
93 | bool Changed = false; | ||||
94 | |||||
95 | // Note: we do not handle TemplateArgument::Expression, to replace it | ||||
96 | // we need the information for the template instance decl. | ||||
97 | |||||
98 | if (Arg.getKind() == TemplateArgument::Template) { | ||||
| |||||
99 | TemplateName TName = Arg.getAsTemplate(); | ||||
100 | Changed = getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); | ||||
101 | if (Changed) { | ||||
102 | Arg = TemplateArgument(TName); | ||||
103 | } | ||||
104 | } else if (Arg.getKind() == TemplateArgument::Type) { | ||||
105 | QualType SubTy = Arg.getAsType(); | ||||
106 | // Check if the type needs more desugaring and recurse. | ||||
107 | QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix); | ||||
108 | if (QTFQ != SubTy) { | ||||
109 | Arg = TemplateArgument(QTFQ); | ||||
110 | Changed = true; | ||||
111 | } | ||||
112 | } | ||||
113 | return Changed; | ||||
114 | } | ||||
115 | |||||
116 | static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, | ||||
117 | const Type *TypePtr, | ||||
118 | bool WithGlobalNsPrefix) { | ||||
119 | // DependentTemplateTypes exist within template declarations and | ||||
120 | // definitions. Therefore we shouldn't encounter them at the end of | ||||
121 | // a translation unit. If we do, the caller has made an error. | ||||
122 | assert(!isa<DependentTemplateSpecializationType>(TypePtr))((!isa<DependentTemplateSpecializationType>(TypePtr)) ? static_cast<void> (0) : __assert_fail ("!isa<DependentTemplateSpecializationType>(TypePtr)" , "/build/llvm-toolchain-snapshot-10~+20191227100609+c3dbd782f1e/clang/lib/AST/QualTypeNames.cpp" , 122, __PRETTY_FUNCTION__)); | ||||
123 | // In case of template specializations, iterate over the arguments | ||||
124 | // and fully qualify them as well. | ||||
125 | if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) { | ||||
126 | bool MightHaveChanged = false; | ||||
127 | SmallVector<TemplateArgument, 4> FQArgs; | ||||
128 | for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); | ||||
129 | I != E; ++I) { | ||||
130 | // Cheap to copy and potentially modified by | ||||
131 | // getFullyQualifedTemplateArgument. | ||||
132 | TemplateArgument Arg(*I); | ||||
133 | MightHaveChanged |= getFullyQualifiedTemplateArgument( | ||||
134 | Ctx, Arg, WithGlobalNsPrefix); | ||||
135 | FQArgs.push_back(Arg); | ||||
136 | } | ||||
137 | |||||
138 | // If a fully qualified arg is different from the unqualified arg, | ||||
139 | // allocate new type in the AST. | ||||
140 | if (MightHaveChanged) { | ||||
141 | QualType QT = Ctx.getTemplateSpecializationType( | ||||
142 | TST->getTemplateName(), FQArgs, | ||||
143 | TST->getCanonicalTypeInternal()); | ||||
144 | // getTemplateSpecializationType returns a fully qualified | ||||
145 | // version of the specialization itself, so no need to qualify | ||||
146 | // it. | ||||
147 | return QT.getTypePtr(); | ||||
148 | } | ||||
149 | } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) { | ||||
150 | // We are asked to fully qualify and we have a Record Type, | ||||
151 | // which can point to a template instantiation with no sugar in any of | ||||
152 | // its template argument, however we still need to fully qualify them. | ||||
153 | |||||
154 | if (const auto *TSTDecl = | ||||
155 | dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) { | ||||
156 | const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); | ||||
157 | |||||
158 | bool MightHaveChanged = false; | ||||
159 | SmallVector<TemplateArgument, 4> FQArgs; | ||||
160 | for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { | ||||
161 | // cheap to copy and potentially modified by | ||||
162 | // getFullyQualifedTemplateArgument | ||||
163 | TemplateArgument Arg(TemplateArgs[I]); | ||||
164 | MightHaveChanged |= getFullyQualifiedTemplateArgument( | ||||
165 | Ctx, Arg, WithGlobalNsPrefix); | ||||
166 | FQArgs.push_back(Arg); | ||||
167 | } | ||||
168 | |||||
169 | // If a fully qualified arg is different from the unqualified arg, | ||||
170 | // allocate new type in the AST. | ||||
171 | if (MightHaveChanged) { | ||||
172 | TemplateName TN(TSTDecl->getSpecializedTemplate()); | ||||
173 | QualType QT = Ctx.getTemplateSpecializationType( | ||||
174 | TN, FQArgs, | ||||
175 | TSTRecord->getCanonicalTypeInternal()); | ||||
176 | // getTemplateSpecializationType returns a fully qualified | ||||
177 | // version of the specialization itself, so no need to qualify | ||||
178 | // it. | ||||
179 | return QT.getTypePtr(); | ||||
180 | } | ||||
181 | } | ||||
182 | } | ||||
183 | return TypePtr; | ||||
184 | } | ||||
185 | |||||
186 | static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, | ||||
187 | bool FullyQualify, | ||||
188 | bool WithGlobalNsPrefix) { | ||||
189 | const DeclContext *DC = D->getDeclContext(); | ||||
190 | if (const auto *NS
| ||||
191 | while (NS
| ||||
192 | // Ignore inline namespace; | ||||
193 | NS = dyn_cast<NamespaceDecl>(NS->getDeclContext()); | ||||
194 | } | ||||
195 | if (NS->getDeclName()) { | ||||
| |||||
196 | return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); | ||||
197 | } | ||||
198 | return nullptr; // no starting '::', no anonymous | ||||
199 | } else if (const auto *TD = dyn_cast<TagDecl>(DC)) { | ||||
200 | return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); | ||||
201 | } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) { | ||||
202 | return createNestedNameSpecifier( | ||||
203 | Ctx, TDD, FullyQualify, WithGlobalNsPrefix); | ||||
204 | } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { | ||||
205 | return NestedNameSpecifier::GlobalSpecifier(Ctx); | ||||
206 | } | ||||
207 | return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false | ||||
208 | } | ||||
209 | |||||
210 | /// Return a fully qualified version of this name specifier. | ||||
211 | static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( | ||||
212 | const ASTContext &Ctx, NestedNameSpecifier *Scope, | ||||
213 | bool WithGlobalNsPrefix) { | ||||
214 | switch (Scope->getKind()) { | ||||
215 | case NestedNameSpecifier::Global: | ||||
216 | // Already fully qualified | ||||
217 | return Scope; | ||||
218 | case NestedNameSpecifier::Namespace: | ||||
219 | return TypeName::createNestedNameSpecifier( | ||||
220 | Ctx, Scope->getAsNamespace(), WithGlobalNsPrefix); | ||||
221 | case NestedNameSpecifier::NamespaceAlias: | ||||
222 | // Namespace aliases are only valid for the duration of the | ||||
223 | // scope where they were introduced, and therefore are often | ||||
224 | // invalid at the end of the TU. So use the namespace name more | ||||
225 | // likely to be valid at the end of the TU. | ||||
226 | return TypeName::createNestedNameSpecifier( | ||||
227 | Ctx, | ||||
228 | Scope->getAsNamespaceAlias()->getNamespace()->getCanonicalDecl(), | ||||
229 | WithGlobalNsPrefix); | ||||
230 | case NestedNameSpecifier::Identifier: | ||||
231 | // A function or some other construct that makes it un-namable | ||||
232 | // at the end of the TU. Skip the current component of the name, | ||||
233 | // but use the name of it's prefix. | ||||
234 | return getFullyQualifiedNestedNameSpecifier( | ||||
235 | Ctx, Scope->getPrefix(), WithGlobalNsPrefix); | ||||
236 | case NestedNameSpecifier::Super: | ||||
237 | case NestedNameSpecifier::TypeSpec: | ||||
238 | case NestedNameSpecifier::TypeSpecWithTemplate: { | ||||
239 | const Type *Type = Scope->getAsType(); | ||||
240 | // Find decl context. | ||||
241 | const TagDecl *TD = nullptr; | ||||
242 | if (const TagType *TagDeclType = Type->getAs<TagType>()) { | ||||
243 | TD = TagDeclType->getDecl(); | ||||
244 | } else { | ||||
245 | TD = Type->getAsCXXRecordDecl(); | ||||
246 | } | ||||
247 | if (TD) { | ||||
248 | return TypeName::createNestedNameSpecifier(Ctx, TD, | ||||
249 | true /*FullyQualified*/, | ||||
250 | WithGlobalNsPrefix); | ||||
251 | } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) { | ||||
252 | return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), | ||||
253 | true /*FullyQualified*/, | ||||
254 | WithGlobalNsPrefix); | ||||
255 | } | ||||
256 | return Scope; | ||||
257 | } | ||||
258 | } | ||||
259 | llvm_unreachable("bad NNS kind")::llvm::llvm_unreachable_internal("bad NNS kind", "/build/llvm-toolchain-snapshot-10~+20191227100609+c3dbd782f1e/clang/lib/AST/QualTypeNames.cpp" , 259); | ||||
260 | } | ||||
261 | |||||
262 | /// Create a nested name specifier for the declaring context of | ||||
263 | /// the type. | ||||
264 | static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( | ||||
265 | const ASTContext &Ctx, const Decl *Decl, | ||||
266 | bool FullyQualified, bool WithGlobalNsPrefix) { | ||||
267 | assert(Decl)((Decl) ? static_cast<void> (0) : __assert_fail ("Decl" , "/build/llvm-toolchain-snapshot-10~+20191227100609+c3dbd782f1e/clang/lib/AST/QualTypeNames.cpp" , 267, __PRETTY_FUNCTION__)); | ||||
268 | |||||
269 | const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); | ||||
270 | const auto *Outer = dyn_cast_or_null<NamedDecl>(DC); | ||||
271 | const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC); | ||||
272 | if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { | ||||
273 | if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) { | ||||
274 | if (ClassTemplateDecl *ClassTempl = | ||||
275 | CxxDecl->getDescribedClassTemplate()) { | ||||
276 | // We are in the case of a type(def) that was declared in a | ||||
277 | // class template but is *not* type dependent. In clang, it | ||||
278 | // gets attached to the class template declaration rather than | ||||
279 | // any specific class template instantiation. This result in | ||||
280 | // 'odd' fully qualified typename: | ||||
281 | // | ||||
282 | // vector<_Tp,_Alloc>::size_type | ||||
283 | // | ||||
284 | // Make the situation is 'useable' but looking a bit odd by | ||||
285 | // picking a random instance as the declaring context. | ||||
286 | if (ClassTempl->spec_begin() != ClassTempl->spec_end()) { | ||||
287 | Decl = *(ClassTempl->spec_begin()); | ||||
288 | Outer = dyn_cast<NamedDecl>(Decl); | ||||
289 | OuterNS = dyn_cast<NamespaceDecl>(Decl); | ||||
290 | } | ||||
291 | } | ||||
292 | } | ||||
293 | |||||
294 | if (OuterNS) { | ||||
295 | return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix); | ||||
296 | } else if (const auto *TD = dyn_cast<TagDecl>(Outer)) { | ||||
297 | return createNestedNameSpecifier( | ||||
298 | Ctx, TD, FullyQualified, WithGlobalNsPrefix); | ||||
299 | } else if (dyn_cast<TranslationUnitDecl>(Outer)) { | ||||
300 | // Context is the TU. Nothing needs to be done. | ||||
301 | return nullptr; | ||||
302 | } else { | ||||
303 | // Decl's context was neither the TU, a namespace, nor a | ||||
304 | // TagDecl, which means it is a type local to a scope, and not | ||||
305 | // accessible at the end of the TU. | ||||
306 | return nullptr; | ||||
307 | } | ||||
308 | } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { | ||||
309 | return NestedNameSpecifier::GlobalSpecifier(Ctx); | ||||
310 | } | ||||
311 | return nullptr; | ||||
312 | } | ||||
313 | |||||
314 | /// Create a nested name specifier for the declaring context of | ||||
315 | /// the type. | ||||
316 | static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( | ||||
317 | const ASTContext &Ctx, const Type *TypePtr, | ||||
318 | bool FullyQualified, bool WithGlobalNsPrefix) { | ||||
319 | if (!TypePtr) return nullptr; | ||||
320 | |||||
321 | Decl *Decl = nullptr; | ||||
322 | // There are probably other cases ... | ||||
323 | if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) { | ||||
324 | Decl = TDT->getDecl(); | ||||
325 | } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) { | ||||
326 | Decl = TagDeclType->getDecl(); | ||||
327 | } else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) { | ||||
328 | Decl = TST->getTemplateName().getAsTemplateDecl(); | ||||
329 | } else { | ||||
330 | Decl = TypePtr->getAsCXXRecordDecl(); | ||||
331 | } | ||||
332 | |||||
333 | if (!Decl) return nullptr; | ||||
334 | |||||
335 | return createNestedNameSpecifierForScopeOf( | ||||
336 | Ctx, Decl, FullyQualified, WithGlobalNsPrefix); | ||||
337 | } | ||||
338 | |||||
339 | NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, | ||||
340 | const NamespaceDecl *Namespace, | ||||
341 | bool WithGlobalNsPrefix) { | ||||
342 | while (Namespace && Namespace->isInline()) { | ||||
343 | // Ignore inline namespace; | ||||
344 | Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext()); | ||||
345 | } | ||||
346 | if (!Namespace
| ||||
347 | |||||
348 | bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces | ||||
349 | return NestedNameSpecifier::Create( | ||||
350 | Ctx, | ||||
351 | createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), | ||||
352 | Namespace); | ||||
353 | } | ||||
354 | |||||
355 | NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, | ||||
356 | const TypeDecl *TD, | ||||
357 | bool FullyQualify, | ||||
358 | bool WithGlobalNsPrefix) { | ||||
359 | return NestedNameSpecifier::Create( | ||||
360 | Ctx, | ||||
361 | createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), | ||||
362 | false /*No TemplateKeyword*/, | ||||
363 | TD->getTypeForDecl()); | ||||
364 | } | ||||
365 | |||||
366 | /// Return the fully qualified type, including fully-qualified | ||||
367 | /// versions of any template parameters. | ||||
368 | QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, | ||||
369 | bool WithGlobalNsPrefix) { | ||||
370 | // In case of myType* we need to strip the pointer first, fully | ||||
371 | // qualify and attach the pointer once again. | ||||
372 | if (isa<PointerType>(QT.getTypePtr())) { | ||||
373 | // Get the qualifiers. | ||||
374 | Qualifiers Quals = QT.getQualifiers(); | ||||
375 | QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); | ||||
376 | QT = Ctx.getPointerType(QT); | ||||
377 | // Add back the qualifiers. | ||||
378 | QT = Ctx.getQualifiedType(QT, Quals); | ||||
379 | return QT; | ||||
380 | } | ||||
381 | |||||
382 | if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) { | ||||
383 | // Get the qualifiers. | ||||
384 | Qualifiers Quals = QT.getQualifiers(); | ||||
385 | // Fully qualify the pointee and class types. | ||||
386 | QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); | ||||
387 | QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx, | ||||
388 | WithGlobalNsPrefix); | ||||
389 | QT = Ctx.getMemberPointerType(QT, Class.getTypePtr()); | ||||
390 | // Add back the qualifiers. | ||||
391 | QT = Ctx.getQualifiedType(QT, Quals); | ||||
392 | return QT; | ||||
393 | } | ||||
394 | |||||
395 | // In case of myType& we need to strip the reference first, fully | ||||
396 | // qualify and attach the reference once again. | ||||
397 | if (isa<ReferenceType>(QT.getTypePtr())) { | ||||
398 | // Get the qualifiers. | ||||
399 | bool IsLValueRefTy = isa<LValueReferenceType>(QT.getTypePtr()); | ||||
400 | Qualifiers Quals = QT.getQualifiers(); | ||||
401 | QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); | ||||
402 | // Add the r- or l-value reference type back to the fully | ||||
403 | // qualified one. | ||||
404 | if (IsLValueRefTy) | ||||
405 | QT = Ctx.getLValueReferenceType(QT); | ||||
406 | else | ||||
407 | QT = Ctx.getRValueReferenceType(QT); | ||||
408 | // Add back the qualifiers. | ||||
409 | QT = Ctx.getQualifiedType(QT, Quals); | ||||
410 | return QT; | ||||
411 | } | ||||
412 | |||||
413 | // Remove the part of the type related to the type being a template | ||||
414 | // parameter (we won't report it as part of the 'type name' and it | ||||
415 | // is actually make the code below to be more complex (to handle | ||||
416 | // those) | ||||
417 | while (isa<SubstTemplateTypeParmType>(QT.getTypePtr())) { | ||||
418 | // Get the qualifiers. | ||||
419 | Qualifiers Quals = QT.getQualifiers(); | ||||
420 | |||||
421 | QT = cast<SubstTemplateTypeParmType>(QT.getTypePtr())->desugar(); | ||||
422 | |||||
423 | // Add back the qualifiers. | ||||
424 | QT = Ctx.getQualifiedType(QT, Quals); | ||||
425 | } | ||||
426 | |||||
427 | NestedNameSpecifier *Prefix = nullptr; | ||||
428 | // Local qualifiers are attached to the QualType outside of the | ||||
429 | // elaborated type. Retrieve them before descending into the | ||||
430 | // elaborated type. | ||||
431 | Qualifiers PrefixQualifiers = QT.getLocalQualifiers(); | ||||
432 | QT = QualType(QT.getTypePtr(), 0); | ||||
433 | ElaboratedTypeKeyword Keyword = ETK_None; | ||||
434 | if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) { | ||||
435 | QT = ETypeInput->getNamedType(); | ||||
436 | assert(!QT.hasLocalQualifiers())((!QT.hasLocalQualifiers()) ? static_cast<void> (0) : __assert_fail ("!QT.hasLocalQualifiers()", "/build/llvm-toolchain-snapshot-10~+20191227100609+c3dbd782f1e/clang/lib/AST/QualTypeNames.cpp" , 436, __PRETTY_FUNCTION__)); | ||||
437 | Keyword = ETypeInput->getKeyword(); | ||||
438 | } | ||||
439 | // Create a nested name specifier if needed. | ||||
440 | Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(), | ||||
441 | true /*FullyQualified*/, | ||||
442 | WithGlobalNsPrefix); | ||||
443 | |||||
444 | // In case of template specializations iterate over the arguments and | ||||
445 | // fully qualify them as well. | ||||
446 | if (isa<const TemplateSpecializationType>(QT.getTypePtr()) || | ||||
447 | isa<const RecordType>(QT.getTypePtr())) { | ||||
448 | // We are asked to fully qualify and we have a Record Type (which | ||||
449 | // may point to a template specialization) or Template | ||||
450 | // Specialization Type. We need to fully qualify their arguments. | ||||
451 | |||||
452 | const Type *TypePtr = getFullyQualifiedTemplateType( | ||||
453 | Ctx, QT.getTypePtr(), WithGlobalNsPrefix); | ||||
454 | QT = QualType(TypePtr, 0); | ||||
455 | } | ||||
456 | if (Prefix || Keyword != ETK_None) { | ||||
457 | QT = Ctx.getElaboratedType(Keyword, Prefix, QT); | ||||
458 | } | ||||
459 | QT = Ctx.getQualifiedType(QT, PrefixQualifiers); | ||||
460 | return QT; | ||||
461 | } | ||||
462 | |||||
463 | std::string getFullyQualifiedName(QualType QT, | ||||
464 | const ASTContext &Ctx, | ||||
465 | const PrintingPolicy &Policy, | ||||
466 | bool WithGlobalNsPrefix) { | ||||
467 | QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix); | ||||
468 | return FQQT.getAsString(Policy); | ||||
469 | } | ||||
470 | |||||
471 | } // end namespace TypeName | ||||
472 | } // end namespace clang |