diff options
Diffstat (limited to 'clang/lib/AST/DeclarationName.cpp')
| -rw-r--r-- | clang/lib/AST/DeclarationName.cpp | 520 | 
1 files changed, 520 insertions, 0 deletions
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp new file mode 100644 index 0000000000000..fe69c71aa3ddf --- /dev/null +++ b/clang/lib/AST/DeclarationName.cpp @@ -0,0 +1,520 @@ +//===- DeclarationName.cpp - Declaration names implementation -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the DeclarationName and DeclarationNameTable +// classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <string> + +using namespace clang; + +static int compareInt(unsigned A, unsigned B) { +  return (A < B ? -1 : (A > B ? 1 : 0)); +} + +int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { +  if (LHS.getNameKind() != RHS.getNameKind()) +    return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1); + +  switch (LHS.getNameKind()) { +  case DeclarationName::Identifier: { +    IdentifierInfo *LII = LHS.castAsIdentifierInfo(); +    IdentifierInfo *RII = RHS.castAsIdentifierInfo(); +    if (!LII) +      return RII ? -1 : 0; +    if (!RII) +      return 1; + +    return LII->getName().compare(RII->getName()); +  } + +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: { +    Selector LHSSelector = LHS.getObjCSelector(); +    Selector RHSSelector = RHS.getObjCSelector(); +    // getNumArgs for ZeroArgSelector returns 0, but we still need to compare. +    if (LHS.getNameKind() == DeclarationName::ObjCZeroArgSelector && +        RHS.getNameKind() == DeclarationName::ObjCZeroArgSelector) { +      return LHSSelector.getAsIdentifierInfo()->getName().compare( +          RHSSelector.getAsIdentifierInfo()->getName()); +    } +    unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs(); +    for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) { +      switch (LHSSelector.getNameForSlot(I).compare( +          RHSSelector.getNameForSlot(I))) { +      case -1: +        return -1; +      case 1: +        return 1; +      default: +        break; +      } +    } + +    return compareInt(LN, RN); +  } + +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +    if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType())) +      return -1; +    if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) +      return 1; +    return 0; + +  case DeclarationName::CXXDeductionGuideName: +    // We never want to compare deduction guide names for templates from +    // different scopes, so just compare the template-name. +    return compare(LHS.getCXXDeductionGuideTemplate()->getDeclName(), +                   RHS.getCXXDeductionGuideTemplate()->getDeclName()); + +  case DeclarationName::CXXOperatorName: +    return compareInt(LHS.getCXXOverloadedOperator(), +                      RHS.getCXXOverloadedOperator()); + +  case DeclarationName::CXXLiteralOperatorName: +    return LHS.getCXXLiteralIdentifier()->getName().compare( +        RHS.getCXXLiteralIdentifier()->getName()); + +  case DeclarationName::CXXUsingDirective: +    return 0; +  } + +  llvm_unreachable("Invalid DeclarationName Kind!"); +} + +static void printCXXConstructorDestructorName(QualType ClassType, +                                              raw_ostream &OS, +                                              PrintingPolicy Policy) { +  // We know we're printing C++ here. Ensure we print types properly. +  Policy.adjustForCPlusPlus(); + +  if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) { +    OS << *ClassRec->getDecl(); +    return; +  } +  if (Policy.SuppressTemplateArgsInCXXConstructors) { +    if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) { +      OS << *InjTy->getDecl(); +      return; +    } +  } +  ClassType.print(OS, Policy); +} + +void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { +  switch (getNameKind()) { +  case DeclarationName::Identifier: +    if (const IdentifierInfo *II = getAsIdentifierInfo()) +      OS << II->getName(); +    return; + +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: +    getObjCSelector().print(OS); +    return; + +  case DeclarationName::CXXConstructorName: +    return printCXXConstructorDestructorName(getCXXNameType(), OS, Policy); + +  case DeclarationName::CXXDestructorName: +    OS << '~'; +    return printCXXConstructorDestructorName(getCXXNameType(), OS, Policy); + +  case DeclarationName::CXXDeductionGuideName: +    OS << "<deduction guide for "; +    getCXXDeductionGuideTemplate()->getDeclName().print(OS, Policy); +    OS << '>'; +    return; + +  case DeclarationName::CXXOperatorName: { +    const char *OpName = getOperatorSpelling(getCXXOverloadedOperator()); +    assert(OpName && "not an overloaded operator"); + +    OS << "operator"; +    if (OpName[0] >= 'a' && OpName[0] <= 'z') +      OS << ' '; +    OS << OpName; +    return; +  } + +  case DeclarationName::CXXLiteralOperatorName: +    OS << "operator\"\"" << getCXXLiteralIdentifier()->getName(); +    return; + +  case DeclarationName::CXXConversionFunctionName: { +    OS << "operator "; +    QualType Type = getCXXNameType(); +    if (const RecordType *Rec = Type->getAs<RecordType>()) { +      OS << *Rec->getDecl(); +      return; +    } +    // We know we're printing C++ here, ensure we print 'bool' properly. +    PrintingPolicy CXXPolicy = Policy; +    CXXPolicy.adjustForCPlusPlus(); +    Type.print(OS, CXXPolicy); +    return; +  } +  case DeclarationName::CXXUsingDirective: +    OS << "<using-directive>"; +    return; +  } + +  llvm_unreachable("Unexpected declaration name kind"); +} + +namespace clang { + +raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) { +  LangOptions LO; +  N.print(OS, PrintingPolicy(LO)); +  return OS; +} + +} // namespace clang + +bool DeclarationName::isDependentName() const { +  QualType T = getCXXNameType(); +  if (!T.isNull() && T->isDependentType()) +    return true; + +  // A class-scope deduction guide in a dependent context has a dependent name. +  auto *TD = getCXXDeductionGuideTemplate(); +  if (TD && TD->getDeclContext()->isDependentContext()) +    return true; + +  return false; +} + +std::string DeclarationName::getAsString() const { +  std::string Result; +  llvm::raw_string_ostream OS(Result); +  OS << *this; +  return OS.str(); +} + +void *DeclarationName::getFETokenInfoSlow() const { +  switch (getNameKind()) { +  case Identifier: +    llvm_unreachable("case Identifier already handled by getFETokenInfo!"); +  case CXXConstructorName: +  case CXXDestructorName: +  case CXXConversionFunctionName: +    return castAsCXXSpecialNameExtra()->FETokenInfo; +  case CXXOperatorName: +    return castAsCXXOperatorIdName()->FETokenInfo; +  case CXXDeductionGuideName: +    return castAsCXXDeductionGuideNameExtra()->FETokenInfo; +  case CXXLiteralOperatorName: +    return castAsCXXLiteralOperatorIdName()->FETokenInfo; +  default: +    llvm_unreachable("DeclarationName has no FETokenInfo!"); +  } +} + +void DeclarationName::setFETokenInfoSlow(void *T) { +  switch (getNameKind()) { +  case Identifier: +    llvm_unreachable("case Identifier already handled by setFETokenInfo!"); +  case CXXConstructorName: +  case CXXDestructorName: +  case CXXConversionFunctionName: +    castAsCXXSpecialNameExtra()->FETokenInfo = T; +    break; +  case CXXOperatorName: +    castAsCXXOperatorIdName()->FETokenInfo = T; +    break; +  case CXXDeductionGuideName: +    castAsCXXDeductionGuideNameExtra()->FETokenInfo = T; +    break; +  case CXXLiteralOperatorName: +    castAsCXXLiteralOperatorIdName()->FETokenInfo = T; +    break; +  default: +    llvm_unreachable("DeclarationName has no FETokenInfo!"); +  } +} + +LLVM_DUMP_METHOD void DeclarationName::dump() const { +  llvm::errs() << *this << '\n'; +} + +DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { +  // Initialize the overloaded operator names. +  for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) +    CXXOperatorNames[Op].Kind = static_cast<OverloadedOperatorKind>(Op); +} + +DeclarationName +DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) { +  Template = cast<TemplateDecl>(Template->getCanonicalDecl()); + +  llvm::FoldingSetNodeID ID; +  ID.AddPointer(Template); + +  void *InsertPos = nullptr; +  if (auto *Name = CXXDeductionGuideNames.FindNodeOrInsertPos(ID, InsertPos)) +    return DeclarationName(Name); + +  auto *Name = new (Ctx) detail::CXXDeductionGuideNameExtra(Template); +  CXXDeductionGuideNames.InsertNode(Name, InsertPos); +  return DeclarationName(Name); +} + +DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) { +  // The type of constructors is unqualified. +  Ty = Ty.getUnqualifiedType(); +  // Do we already have this C++ constructor name ? +  llvm::FoldingSetNodeID ID; +  ID.AddPointer(Ty.getAsOpaquePtr()); +  void *InsertPos = nullptr; +  if (auto *Name = CXXConstructorNames.FindNodeOrInsertPos(ID, InsertPos)) +    return {Name, DeclarationName::StoredCXXConstructorName}; + +  // We have to create it. +  auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty); +  CXXConstructorNames.InsertNode(SpecialName, InsertPos); +  return {SpecialName, DeclarationName::StoredCXXConstructorName}; +} + +DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) { +  // The type of destructors is unqualified. +  Ty = Ty.getUnqualifiedType(); +  // Do we already have this C++ destructor name ? +  llvm::FoldingSetNodeID ID; +  ID.AddPointer(Ty.getAsOpaquePtr()); +  void *InsertPos = nullptr; +  if (auto *Name = CXXDestructorNames.FindNodeOrInsertPos(ID, InsertPos)) +    return {Name, DeclarationName::StoredCXXDestructorName}; + +  // We have to create it. +  auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty); +  CXXDestructorNames.InsertNode(SpecialName, InsertPos); +  return {SpecialName, DeclarationName::StoredCXXDestructorName}; +} + +DeclarationName +DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) { +  // Do we already have this C++ conversion function name ? +  llvm::FoldingSetNodeID ID; +  ID.AddPointer(Ty.getAsOpaquePtr()); +  void *InsertPos = nullptr; +  if (auto *Name = +          CXXConversionFunctionNames.FindNodeOrInsertPos(ID, InsertPos)) +    return {Name, DeclarationName::StoredCXXConversionFunctionName}; + +  // We have to create it. +  auto *SpecialName = new (Ctx) detail::CXXSpecialNameExtra(Ty); +  CXXConversionFunctionNames.InsertNode(SpecialName, InsertPos); +  return {SpecialName, DeclarationName::StoredCXXConversionFunctionName}; +} + +DeclarationName +DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, +                                        CanQualType Ty) { +  switch (Kind) { +  case DeclarationName::CXXConstructorName: +    return getCXXConstructorName(Ty); +  case DeclarationName::CXXDestructorName: +    return getCXXDestructorName(Ty); +  case DeclarationName::CXXConversionFunctionName: +    return getCXXConversionFunctionName(Ty); +  default: +    llvm_unreachable("Invalid kind in getCXXSpecialName!"); +  } +} + +DeclarationName +DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { +  llvm::FoldingSetNodeID ID; +  ID.AddPointer(II); + +  void *InsertPos = nullptr; +  if (auto *Name = CXXLiteralOperatorNames.FindNodeOrInsertPos(ID, InsertPos)) +    return DeclarationName(Name); + +  auto *LiteralName = new (Ctx) detail::CXXLiteralOperatorIdName(II); +  CXXLiteralOperatorNames.InsertNode(LiteralName, InsertPos); +  return DeclarationName(LiteralName); +} + +DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) { +  switch (Name.getNameKind()) { +  case DeclarationName::Identifier: +  case DeclarationName::CXXDeductionGuideName: +    break; +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +    NamedType.TInfo = nullptr; +    break; +  case DeclarationName::CXXOperatorName: +    CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding(); +    CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding(); +    break; +  case DeclarationName::CXXLiteralOperatorName: +    CXXLiteralOperatorName.OpNameLoc = SourceLocation().getRawEncoding(); +    break; +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: +    // FIXME: ? +    break; +  case DeclarationName::CXXUsingDirective: +    break; +  } +} + +bool DeclarationNameInfo::containsUnexpandedParameterPack() const { +  switch (Name.getNameKind()) { +  case DeclarationName::Identifier: +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: +  case DeclarationName::CXXOperatorName: +  case DeclarationName::CXXLiteralOperatorName: +  case DeclarationName::CXXUsingDirective: +  case DeclarationName::CXXDeductionGuideName: +    return false; + +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +    if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) +      return TInfo->getType()->containsUnexpandedParameterPack(); + +    return Name.getCXXNameType()->containsUnexpandedParameterPack(); +  } +  llvm_unreachable("All name kinds handled."); +} + +bool DeclarationNameInfo::isInstantiationDependent() const { +  switch (Name.getNameKind()) { +  case DeclarationName::Identifier: +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: +  case DeclarationName::CXXOperatorName: +  case DeclarationName::CXXLiteralOperatorName: +  case DeclarationName::CXXUsingDirective: +  case DeclarationName::CXXDeductionGuideName: +    return false; + +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +    if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) +      return TInfo->getType()->isInstantiationDependentType(); + +    return Name.getCXXNameType()->isInstantiationDependentType(); +  } +  llvm_unreachable("All name kinds handled."); +} + +std::string DeclarationNameInfo::getAsString() const { +  std::string Result; +  llvm::raw_string_ostream OS(Result); +  printName(OS); +  return OS.str(); +} + +void DeclarationNameInfo::printName(raw_ostream &OS) const { +  switch (Name.getNameKind()) { +  case DeclarationName::Identifier: +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: +  case DeclarationName::CXXOperatorName: +  case DeclarationName::CXXLiteralOperatorName: +  case DeclarationName::CXXUsingDirective: +  case DeclarationName::CXXDeductionGuideName: +    OS << Name; +    return; + +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +    if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) { +      if (Name.getNameKind() == DeclarationName::CXXDestructorName) +        OS << '~'; +      else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) +        OS << "operator "; +      LangOptions LO; +      LO.CPlusPlus = true; +      LO.Bool = true; +      PrintingPolicy PP(LO); +      PP.SuppressScope = true; +      OS << TInfo->getType().getAsString(PP); +    } else +      OS << Name; +    return; +  } +  llvm_unreachable("Unexpected declaration name kind"); +} + +SourceLocation DeclarationNameInfo::getEndLocPrivate() const { +  switch (Name.getNameKind()) { +  case DeclarationName::Identifier: +  case DeclarationName::CXXDeductionGuideName: +    return NameLoc; + +  case DeclarationName::CXXOperatorName: { +    unsigned raw = LocInfo.CXXOperatorName.EndOpNameLoc; +    return SourceLocation::getFromRawEncoding(raw); +  } + +  case DeclarationName::CXXLiteralOperatorName: { +    unsigned raw = LocInfo.CXXLiteralOperatorName.OpNameLoc; +    return SourceLocation::getFromRawEncoding(raw); +  } + +  case DeclarationName::CXXConstructorName: +  case DeclarationName::CXXDestructorName: +  case DeclarationName::CXXConversionFunctionName: +    if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) +      return TInfo->getTypeLoc().getEndLoc(); +    else +      return NameLoc; + +    // DNInfo work in progress: FIXME. +  case DeclarationName::ObjCZeroArgSelector: +  case DeclarationName::ObjCOneArgSelector: +  case DeclarationName::ObjCMultiArgSelector: +  case DeclarationName::CXXUsingDirective: +    return NameLoc; +  } +  llvm_unreachable("Unexpected declaration name kind"); +}  | 
