Bug Summary

File:tools/clang/lib/AST/QualTypeNames.cpp
Warning:line 198, column 9
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

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