| //===- 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/OpenMPClause.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) const { |
| switch (getNameKind()) { |
| case DeclarationName::Identifier: |
| if (const IdentifierInfo *II = getAsIdentifierInfo()) { |
| StringRef Name = II->getName(); |
| // If this is a mangled OpenMP variant name we strip off the mangling for |
| // printing. It should not be visible to the user at all. |
| if (II->isMangledOpenMPVariantName()) { |
| std::pair<StringRef, StringRef> NameContextPair = |
| Name.split(getOpenMPVariantManglingSeparatorStr()); |
| OS << NameContextPair.first << "[" |
| << OMPTraitInfo(NameContextPair.second) << "]"; |
| } else { |
| OS << Name; |
| } |
| } |
| 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: |
| setNamedTypeLoc(nullptr); |
| break; |
| case DeclarationName::CXXOperatorName: |
| setCXXOperatorNameRange(SourceRange()); |
| break; |
| case DeclarationName::CXXLiteralOperatorName: |
| setCXXLiteralOperatorNameLoc(SourceLocation()); |
| 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.getNamedTypeInfo()) |
| 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.getNamedTypeInfo()) |
| 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); |
| OS << *this; |
| return OS.str(); |
| } |
| |
| raw_ostream &clang::operator<<(raw_ostream &OS, DeclarationNameInfo DNInfo) { |
| LangOptions LO; |
| DNInfo.printName(OS, PrintingPolicy(LangOptions())); |
| return OS; |
| } |
| |
| void DeclarationNameInfo::printName(raw_ostream &OS, PrintingPolicy Policy) 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: |
| Name.print(OS, Policy); |
| return; |
| |
| case DeclarationName::CXXConstructorName: |
| case DeclarationName::CXXDestructorName: |
| case DeclarationName::CXXConversionFunctionName: |
| if (TypeSourceInfo *TInfo = LocInfo.getNamedTypeInfo()) { |
| if (Name.getNameKind() == DeclarationName::CXXDestructorName) |
| OS << '~'; |
| else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) |
| OS << "operator "; |
| LangOptions LO; |
| Policy.adjustForCPlusPlus(); |
| Policy.SuppressScope = true; |
| OS << TInfo->getType().getAsString(Policy); |
| } else |
| Name.print(OS, Policy); |
| 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: |
| return LocInfo.getCXXOperatorNameEndLoc(); |
| |
| case DeclarationName::CXXLiteralOperatorName: |
| return LocInfo.getCXXLiteralOperatorNameLoc(); |
| |
| case DeclarationName::CXXConstructorName: |
| case DeclarationName::CXXDestructorName: |
| case DeclarationName::CXXConversionFunctionName: |
| if (TypeSourceInfo *TInfo = LocInfo.getNamedTypeInfo()) |
| 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"); |
| } |