//===- 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 #include #include #include 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()) { OS << *ClassRec->getDecl(); return; } if (Policy.SuppressTemplateArgsInCXXConstructors) { if (auto *InjTy = ClassType->getAs()) { 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 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 << "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()) { 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 << ""; 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 Result; } 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(Op); } DeclarationName DeclarationNameTable::getCXXDeductionGuideName(TemplateDecl *Template) { Template = cast(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 Result; } 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"); }