Coverage Report

Created: 2020-02-25 14:32

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