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
18namespace clang {
19
20namespace 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.
30static 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.
45static NestedNameSpecifier *createNestedNameSpecifier(
46    const ASTContext &Ctx, const TypeDecl *TD,
47    bool FullyQualify, bool WithGlobalNsPrefix);
48
49static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
50    const ASTContext &Ctx, const Decl *decl,
51    bool FullyQualified, bool WithGlobalNsPrefix);
52
53static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
54    const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
55
56static 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);
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
90static 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
116static 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));
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
186static 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 = dyn_cast<NamespaceDecl>(DC)) {
191    while (NS && NS->isInline()) {
192      // Ignore inline namespace;
193      NS = dyn_cast<NamespaceDecl>(NS->getDeclContext());
194    }
195    if (NS && 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.
211static 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");
260}
261
262/// Create a nested name specifier for the declaring context of
263/// the type.
264static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
265    const ASTContext &Ctx, const Decl *Decl,
266    bool FullyQualified, bool WithGlobalNsPrefix) {
267  assert(Decl);
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.
316static 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
339NestedNameSpecifier *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) return nullptr;
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
355NestedNameSpecifier *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.
368QualType 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());
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
463std::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
473