|  | //===- DeclarationName.cpp - Declaration names implementation -------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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: { | 
|  | static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = { | 
|  | nullptr, | 
|  | #define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly)  \ | 
|  | Spelling, | 
|  | #include "clang/Basic/OperatorKinds.def" | 
|  | }; | 
|  | const char *OpName = OperatorNames[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"); | 
|  | } |