Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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
18
                                              bool WithGlobalNsPrefix) {
93
18
  bool Changed = false;
94
18
95
18
  // Note: we do not handle TemplateArgument::Expression, to replace it
96
18
  // we need the information for the template instance decl.
97
18
98
18
  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
18
  } else if (Arg.getKind() == TemplateArgument::Type) {
105
18
    QualType SubTy = Arg.getAsType();
106
18
    // Check if the type needs more desugaring and recurse.
107
18
    QualType QTFQ = getFullyQualifiedType(SubTy, Ctx, WithGlobalNsPrefix);
108
18
    if (QTFQ != SubTy) {
109
9
      Arg = TemplateArgument(QTFQ);
110
9
      Changed = true;
111
9
    }
112
18
  }
113
18
  return Changed;
114
18
}
115
116
static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
117
                                                 const Type *TypePtr,
118
25
                                                 bool WithGlobalNsPrefix) {
119
25
  // DependentTemplateTypes exist within template declarations and
120
25
  // definitions. Therefore we shouldn't encounter them at the end of
121
25
  // a translation unit. If we do, the caller has made an error.
122
25
  assert(!isa<DependentTemplateSpecializationType>(TypePtr));
123
25
  // In case of template specializations, iterate over the arguments
124
25
  // and fully qualify them as well.
125
25
  if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
126
9
    bool MightHaveChanged = false;
127
9
    SmallVector<TemplateArgument, 4> FQArgs;
128
9
    for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
129
27
         I != E; 
++I18
) {
130
18
      // Cheap to copy and potentially modified by
131
18
      // getFullyQualifedTemplateArgument.
132
18
      TemplateArgument Arg(*I);
133
18
      MightHaveChanged |= getFullyQualifiedTemplateArgument(
134
18
          Ctx, Arg, WithGlobalNsPrefix);
135
18
      FQArgs.push_back(Arg);
136
18
    }
137
9
138
9
    // If a fully qualified arg is different from the unqualified arg,
139
9
    // allocate new type in the AST.
140
9
    if (MightHaveChanged) {
141
4
      QualType QT = Ctx.getTemplateSpecializationType(
142
4
          TST->getTemplateName(), FQArgs,
143
4
          TST->getCanonicalTypeInternal());
144
4
      // getTemplateSpecializationType returns a fully qualified
145
4
      // version of the specialization itself, so no need to qualify
146
4
      // it.
147
4
      return QT.getTypePtr();
148
4
    }
149
16
  } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
150
16
    // We are asked to fully qualify and we have a Record Type,
151
16
    // which can point to a template instantiation with no sugar in any of
152
16
    // its template argument, however we still need to fully qualify them.
153
16
154
16
    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
21
    }
182
16
  }
183
21
  return TypePtr;
184
21
}
185
186
static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
187
                                           bool FullyQualify,
188
104
                                           bool WithGlobalNsPrefix) {
189
104
  const DeclContext *DC = D->getDeclContext();
190
104
  if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
191
43
    while (NS && NS->isInline()) {
192
0
      // Ignore inline namespace;
193
0
      NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
194
0
    }
195
43
    if (NS->getDeclName()) {
196
43
      return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
197
43
    }
198
0
    return nullptr;  // no starting '::', no anonymous
199
61
  } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
200
0
    return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
201
61
  } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
202
0
    return createNestedNameSpecifier(
203
0
        Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
204
61
  } else if (WithGlobalNsPrefix && 
DC->isTranslationUnit()5
) {
205
5
    return NestedNameSpecifier::GlobalSpecifier(Ctx);
206
5
  }
207
56
  return nullptr;  // no starting '::' if |WithGlobalNsPrefix| is false
208
56
}
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
151
    bool FullyQualified, bool WithGlobalNsPrefix) {
267
151
  assert(Decl);
268
151
269
151
  const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
270
151
  const auto *Outer = dyn_cast_or_null<NamedDecl>(DC);
271
151
  const auto *OuterNS = dyn_cast_or_null<NamespaceDecl>(DC);
272
151
  if (Outer && 
!(65
OuterNS65
&&
OuterNS->isAnonymousNamespace()42
)) {
273
62
    if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
274
22
      if (ClassTemplateDecl *ClassTempl =
275
2
              CxxDecl->getDescribedClassTemplate()) {
276
2
        // We are in the case of a type(def) that was declared in a
277
2
        // class template but is *not* type dependent.  In clang, it
278
2
        // gets attached to the class template declaration rather than
279
2
        // any specific class template instantiation.  This result in
280
2
        // 'odd' fully qualified typename:
281
2
        //
282
2
        //    vector<_Tp,_Alloc>::size_type
283
2
        //
284
2
        // Make the situation is 'useable' but looking a bit odd by
285
2
        // picking a random instance as the declaring context.
286
2
        if (ClassTempl->spec_begin() != ClassTempl->spec_end()) {
287
2
          Decl = *(ClassTempl->spec_begin());
288
2
          Outer = dyn_cast<NamedDecl>(Decl);
289
2
          OuterNS = dyn_cast<NamespaceDecl>(Decl);
290
2
        }
291
2
      }
292
22
    }
293
62
294
62
    if (OuterNS) {
295
39
      return createNestedNameSpecifier(Ctx, OuterNS, WithGlobalNsPrefix);
296
39
    } else 
if (const auto *23
TD23
= dyn_cast<TagDecl>(Outer)) {
297
22
      return createNestedNameSpecifier(
298
22
          Ctx, TD, FullyQualified, WithGlobalNsPrefix);
299
22
    } else 
if (1
dyn_cast<TranslationUnitDecl>(Outer)1
) {
300
0
      // Context is the TU. Nothing needs to be done.
301
0
      return nullptr;
302
1
    } else {
303
1
      // Decl's context was neither the TU, a namespace, nor a
304
1
      // TagDecl, which means it is a type local to a scope, and not
305
1
      // accessible at the end of the TU.
306
1
      return nullptr;
307
1
    }
308
89
  } else if (WithGlobalNsPrefix && 
DC->isTranslationUnit()2
) {
309
1
    return NestedNameSpecifier::GlobalSpecifier(Ctx);
310
1
  }
311
88
  return nullptr;
312
88
}
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
165
    bool FullyQualified, bool WithGlobalNsPrefix) {
319
165
  if (!TypePtr) 
return nullptr0
;
320
165
321
165
  Decl *Decl = nullptr;
322
165
  // There are probably other cases ...
323
165
  if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
324
10
    Decl = TDT->getDecl();
325
155
  } else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
326
132
    Decl = TagDeclType->getDecl();
327
132
  } else 
if (const auto *23
TST23
= dyn_cast<TemplateSpecializationType>(TypePtr)) {
328
9
    Decl = TST->getTemplateName().getAsTemplateDecl();
329
14
  } else {
330
14
    Decl = TypePtr->getAsCXXRecordDecl();
331
14
  }
332
165
333
165
  if (!Decl) 
return nullptr14
;
334
151
335
151
  return createNestedNameSpecifierForScopeOf(
336
151
      Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
337
151
}
338
339
NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
340
                                               const NamespaceDecl *Namespace,
341
82
                                               bool WithGlobalNsPrefix) {
342
82
  while (Namespace && Namespace->isInline()) {
343
0
    // Ignore inline namespace;
344
0
    Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
345
0
  }
346
82
  if (!Namespace) 
return nullptr0
;
347
82
348
82
  bool FullyQualified = true;  // doesn't matter, DeclContexts are namespaces
349
82
  return NestedNameSpecifier::Create(
350
82
      Ctx,
351
82
      createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
352
82
      Namespace);
353
82
}
354
355
NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
356
                                               const TypeDecl *TD,
357
                                               bool FullyQualify,
358
22
                                               bool WithGlobalNsPrefix) {
359
22
  return NestedNameSpecifier::Create(
360
22
      Ctx,
361
22
      createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
362
22
      false /*No TemplateKeyword*/,
363
22
      TD->getTypeForDecl());
364
22
}
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
168
                               bool WithGlobalNsPrefix) {
370
168
  // In case of myType* we need to strip the pointer first, fully
371
168
  // qualify and attach the pointer once again.
372
168
  if (isa<PointerType>(QT.getTypePtr())) {
373
2
    // Get the qualifiers.
374
2
    Qualifiers Quals = QT.getQualifiers();
375
2
    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
376
2
    QT = Ctx.getPointerType(QT);
377
2
    // Add back the qualifiers.
378
2
    QT = Ctx.getQualifiedType(QT, Quals);
379
2
    return QT;
380
2
  }
381
166
382
166
  if (auto *MPT = dyn_cast<MemberPointerType>(QT.getTypePtr())) {
383
1
    // Get the qualifiers.
384
1
    Qualifiers Quals = QT.getQualifiers();
385
1
    // Fully qualify the pointee and class types.
386
1
    QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
387
1
    QualType Class = getFullyQualifiedType(QualType(MPT->getClass(), 0), Ctx,
388
1
                                           WithGlobalNsPrefix);
389
1
    QT = Ctx.getMemberPointerType(QT, Class.getTypePtr());
390
1
    // Add back the qualifiers.
391
1
    QT = Ctx.getQualifiedType(QT, Quals);
392
1
    return QT;
393
1
  }
394
165
395
165
  // In case of myType& we need to strip the reference first, fully
396
165
  // qualify and attach the reference once again.
397
165
  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
165
413
165
  // Remove the part of the type related to the type being a template
414
165
  // parameter (we won't report it as part of the 'type name' and it
415
165
  // is actually make the code below to be more complex (to handle
416
165
  // those)
417
165
  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
165
427
165
  NestedNameSpecifier *Prefix = nullptr;
428
165
  // Local qualifiers are attached to the QualType outside of the
429
165
  // elaborated type.  Retrieve them before descending into the
430
165
  // elaborated type.
431
165
  Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
432
165
  QT = QualType(QT.getTypePtr(), 0);
433
165
  ElaboratedTypeKeyword Keyword = ETK_None;
434
165
  if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
435
15
    QT = ETypeInput->getNamedType();
436
15
    assert(!QT.hasLocalQualifiers());
437
15
    Keyword = ETypeInput->getKeyword();
438
15
  }
439
165
  // Create a nested name specifier if needed.
440
165
  Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
441
165
                                               true /*FullyQualified*/,
442
165
                                               WithGlobalNsPrefix);
443
165
444
165
  // In case of template specializations iterate over the arguments and
445
165
  // fully qualify them as well.
446
165
  if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
447
165
      
isa<const RecordType>(QT.getTypePtr())156
) {
448
25
    // We are asked to fully qualify and we have a Record Type (which
449
25
    // may point to a template specialization) or Template
450
25
    // Specialization Type. We need to fully qualify their arguments.
451
25
452
25
    const Type *TypePtr = getFullyQualifiedTemplateType(
453
25
        Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
454
25
    QT = QualType(TypePtr, 0);
455
25
  }
456
165
  if (Prefix || 
Keyword != ETK_None103
) {
457
64
    QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
458
64
  }
459
165
  QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
460
165
  return QT;
461
165
}
462
463
std::string getFullyQualifiedName(QualType QT,
464
                                  const ASTContext &Ctx,
465
                                  const PrintingPolicy &Policy,
466
31
                                  bool WithGlobalNsPrefix) {
467
31
  QualType FQQT = getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
468
31
  return FQQT.getAsString(Policy);
469
31
}
470
471
}  // end namespace TypeName
472
}  // end namespace clang