mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-01 05:46:07 +00:00

This avoids an unnecessary copy required by 'return OS.str()', allowing instead for NRVO or implicit move. The .str() call (which flushes the stream) is no longer required since 65b13610a5226b84889b923bae884ba395ad084d, which made raw_string_ostream unbuffered by default. Differential Revision: https://reviews.llvm.org/D115374
533 lines
17 KiB
C++
533 lines
17 KiB
C++
//===- 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 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<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 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");
|
|
}
|