[clang] Improve nested name specifier AST representation (#147835)
This is a major change on how we represent nested name qualifications in the AST. * The nested name specifier itself and how it's stored is changed. The prefixes for types are handled within the type hierarchy, which makes canonicalization for them super cheap, no memory allocation required. Also translating a type into nested name specifier form becomes a no-op. An identifier is stored as a DependentNameType. The nested name specifier gains a lightweight handle class, to be used instead of passing around pointers, which is similar to what is implemented for TemplateName. There is still one free bit available, and this handle can be used within a PointerUnion and PointerIntPair, which should keep bit-packing aficionados happy. * The ElaboratedType node is removed, all type nodes in which it could previously apply to can now store the elaborated keyword and name qualifier, tail allocating when present. * TagTypes can now point to the exact declaration found when producing these, as opposed to the previous situation of there only existing one TagType per entity. This increases the amount of type sugar retained, and can have several applications, for example in tracking module ownership, and other tools which care about source file origins, such as IWYU. These TagTypes are lazily allocated, in order to limit the increase in AST size. This patch offers a great performance benefit. It greatly improves compilation time for [stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for `test_on2.cpp` in that project, which is the slowest compiling test, this patch improves `-c` compilation time by about 7.2%, with the `-fsyntax-only` improvement being at ~12%. This has great results on compile-time-tracker as well:  This patch also further enables other optimziations in the future, and will reduce the performance impact of template specialization resugaring when that lands. It has some other miscelaneous drive-by fixes. About the review: Yes the patch is huge, sorry about that. Part of the reason is that I started by the nested name specifier part, before the ElaboratedType part, but that had a huge performance downside, as ElaboratedType is a big performance hog. I didn't have the steam to go back and change the patch after the fact. There is also a lot of internal API changes, and it made sense to remove ElaboratedType in one go, versus removing it from one type at a time, as that would present much more churn to the users. Also, the nested name specifier having a different API avoids missing changes related to how prefixes work now, which could make existing code compile but not work. How to review: The important changes are all in `clang/include/clang/AST` and `clang/lib/AST`, with also important changes in `clang/lib/Sema/TreeTransform.h`. The rest and bulk of the changes are mostly consequences of the changes in API. PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just for easier to rebasing. I plan to rename it back after this lands. Fixes #136624 Fixes https://github.com/llvm/llvm-project/issues/43179 Fixes https://github.com/llvm/llvm-project/issues/68670 Fixes https://github.com/llvm/llvm-project/issues/92757
This commit is contained in:
parent
fc44a4fcd3
commit
91cdd35008
@ -31,24 +31,9 @@ llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
|
||||
return Splitted;
|
||||
}
|
||||
|
||||
SourceLocation startLocationForType(TypeLoc TLoc) {
|
||||
// For elaborated types (e.g. `struct a::A`) we want the portion after the
|
||||
// `struct` but including the namespace qualifier, `a::`.
|
||||
if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
|
||||
NestedNameSpecifierLoc NestedNameSpecifier =
|
||||
TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
|
||||
if (NestedNameSpecifier.getNestedNameSpecifier())
|
||||
return NestedNameSpecifier.getBeginLoc();
|
||||
TLoc = TLoc.getNextTypeLoc();
|
||||
}
|
||||
return TLoc.getBeginLoc();
|
||||
}
|
||||
|
||||
SourceLocation endLocationForType(TypeLoc TLoc) {
|
||||
// Dig past any namespace or keyword qualifications.
|
||||
while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
|
||||
TLoc.getTypeLocClass() == TypeLoc::Qualified)
|
||||
TLoc = TLoc.getNextTypeLoc();
|
||||
if (auto QTL = TLoc.getAs<QualifiedTypeLoc>())
|
||||
TLoc = QTL.getUnqualifiedLoc();
|
||||
|
||||
// The location for template specializations (e.g. Foo<int>) includes the
|
||||
// templated types in its location range. We want to restrict this to just
|
||||
@ -550,8 +535,8 @@ void ChangeNamespaceTool::run(
|
||||
Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
|
||||
"nested_specifier_loc")) {
|
||||
SourceLocation Start = Specifier->getBeginLoc();
|
||||
SourceLocation End = endLocationForType(Specifier->getTypeLoc());
|
||||
fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
|
||||
SourceLocation End = endLocationForType(Specifier->castAsTypeLoc());
|
||||
fixTypeLoc(Result, Start, End, Specifier->castAsTypeLoc());
|
||||
} else if (const auto *BaseInitializer =
|
||||
Result.Nodes.getNodeAs<CXXCtorInitializer>(
|
||||
"base_initializer")) {
|
||||
@ -562,19 +547,16 @@ void ChangeNamespaceTool::run(
|
||||
// filtered by matchers in some cases, e.g. the type is templated. We should
|
||||
// handle the record type qualifier instead.
|
||||
TypeLoc Loc = *TLoc;
|
||||
while (Loc.getTypeLocClass() == TypeLoc::Qualified)
|
||||
Loc = Loc.getNextTypeLoc();
|
||||
if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
|
||||
NestedNameSpecifierLoc NestedNameSpecifier =
|
||||
Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
|
||||
// FIXME: avoid changing injected class names.
|
||||
if (auto *NNS = NestedNameSpecifier.getNestedNameSpecifier()) {
|
||||
const Type *SpecifierType = NNS->getAsType();
|
||||
if (SpecifierType && SpecifierType->isRecordType())
|
||||
return;
|
||||
}
|
||||
}
|
||||
fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
|
||||
if (auto QTL = Loc.getAs<QualifiedTypeLoc>())
|
||||
Loc = QTL.getUnqualifiedLoc();
|
||||
// FIXME: avoid changing injected class names.
|
||||
if (NestedNameSpecifier NestedNameSpecifier =
|
||||
Loc.getPrefix().getNestedNameSpecifier();
|
||||
NestedNameSpecifier.getKind() == NestedNameSpecifier::Kind::Type &&
|
||||
NestedNameSpecifier.getAsType()->isRecordType())
|
||||
return;
|
||||
fixTypeLoc(Result, Loc.getNonElaboratedBeginLoc(), endLocationForType(Loc),
|
||||
Loc);
|
||||
} else if (const auto *VarRef =
|
||||
Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
|
||||
const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
|
||||
@ -588,10 +570,9 @@ void ChangeNamespaceTool::run(
|
||||
} else if (const auto *EnumConstRef =
|
||||
Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
|
||||
// Do not rename the reference if it is already scoped by the EnumDecl name.
|
||||
if (EnumConstRef->hasQualifier() &&
|
||||
EnumConstRef->getQualifier()->getKind() ==
|
||||
NestedNameSpecifier::SpecifierKind::TypeSpec &&
|
||||
EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
|
||||
if (NestedNameSpecifier Qualifier = EnumConstRef->getQualifier();
|
||||
Qualifier.getKind() == NestedNameSpecifier::Kind::Type &&
|
||||
Qualifier.getAsType()->isEnumeralType())
|
||||
return;
|
||||
const auto *EnumConstDecl =
|
||||
Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
|
||||
|
@ -902,8 +902,8 @@ parseBases(RecordInfo &I, const CXXRecordDecl *D, bool IsFileInRootDir,
|
||||
return;
|
||||
for (const CXXBaseSpecifier &B : D->bases()) {
|
||||
if (const RecordType *Ty = B.getType()->getAs<RecordType>()) {
|
||||
if (const CXXRecordDecl *Base =
|
||||
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition())) {
|
||||
if (const CXXRecordDecl *Base = cast_or_null<CXXRecordDecl>(
|
||||
Ty->getOriginalDecl()->getDefinition())) {
|
||||
// Initialized without USR and name, this will be set in the following
|
||||
// if-else stmt.
|
||||
BaseRecordInfo BI(
|
||||
|
@ -216,8 +216,7 @@ void FindAllSymbols::registerMatchers(MatchFinder *MatchFinder) {
|
||||
// Uses of most types: just look at what the typeLoc refers to.
|
||||
MatchFinder->addMatcher(
|
||||
typeLoc(isExpansionInMainFile(),
|
||||
loc(qualType(allOf(unless(elaboratedType()),
|
||||
hasDeclaration(Types.bind("use")))))),
|
||||
loc(qualType(hasDeclaration(Types.bind("use"))))),
|
||||
this);
|
||||
// Uses of typedefs: these are often transparent to hasDeclaration, so we need
|
||||
// to handle them explicitly.
|
||||
|
@ -533,7 +533,8 @@ void ClangTidyDiagnosticConsumer::forwardDiagnostic(const Diagnostic &Info) {
|
||||
Builder << reinterpret_cast<const NamedDecl *>(Info.getRawArg(Index));
|
||||
break;
|
||||
case clang::DiagnosticsEngine::ak_nestednamespec:
|
||||
Builder << reinterpret_cast<NestedNameSpecifier *>(Info.getRawArg(Index));
|
||||
Builder << NestedNameSpecifier::getFromVoidPointer(
|
||||
reinterpret_cast<void *>(Info.getRawArg(Index)));
|
||||
break;
|
||||
case clang::DiagnosticsEngine::ak_declcontext:
|
||||
Builder << reinterpret_cast<DeclContext *>(Info.getRawArg(Index));
|
||||
|
@ -43,7 +43,8 @@ static bool isDerivedClassBefriended(const CXXRecordDecl *CRTP,
|
||||
return false;
|
||||
}
|
||||
|
||||
return FriendType->getType()->getAsCXXRecordDecl() == Derived;
|
||||
return declaresSameEntity(FriendType->getType()->getAsCXXRecordDecl(),
|
||||
Derived);
|
||||
});
|
||||
}
|
||||
|
||||
@ -55,7 +56,8 @@ getDerivedParameter(const ClassTemplateSpecializationDecl *CRTP,
|
||||
CRTP->getTemplateArgs().asArray(), [&](const TemplateArgument &Arg) {
|
||||
++Idx;
|
||||
return Arg.getKind() == TemplateArgument::Type &&
|
||||
Arg.getAsType()->getAsCXXRecordDecl() == Derived;
|
||||
declaresSameEntity(Arg.getAsType()->getAsCXXRecordDecl(),
|
||||
Derived);
|
||||
});
|
||||
|
||||
return AnyOf ? CRTP->getSpecializedTemplate()
|
||||
|
@ -577,7 +577,7 @@ approximateImplicitConversion(const TheCheck &Check, QualType LType,
|
||||
ImplicitConversionModellingMode ImplicitMode);
|
||||
|
||||
static inline bool isUselessSugar(const Type *T) {
|
||||
return isa<AttributedType, DecayedType, ElaboratedType, ParenType>(T);
|
||||
return isa<AttributedType, DecayedType, ParenType>(T);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -1040,7 +1040,9 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
|
||||
const auto *ToRecord = To->getAsCXXRecordDecl();
|
||||
if (isDerivedToBase(FromRecord, ToRecord)) {
|
||||
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdConv. Derived To Base.\n");
|
||||
WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply};
|
||||
WorkType = QualType{
|
||||
ToRecord->getASTContext().getCanonicalTagType(ToRecord)->getTypePtr(),
|
||||
FastQualifiersToApply};
|
||||
}
|
||||
|
||||
if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) {
|
||||
@ -1072,9 +1074,9 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
|
||||
WorkType = To;
|
||||
}
|
||||
|
||||
if (WorkType == To) {
|
||||
if (Ctx.hasSameType(WorkType, To)) {
|
||||
LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Reached 'To' type.\n");
|
||||
return {WorkType};
|
||||
return {Ctx.getCommonSugaredType(WorkType, To)};
|
||||
}
|
||||
|
||||
LLVM_DEBUG(llvm::dbgs() << "<<< approximateStdConv. Did not reach 'To'.\n");
|
||||
@ -1219,7 +1221,7 @@ tryConversionOperators(const TheCheck &Check, const CXXRecordDecl *RD,
|
||||
|
||||
if (std::optional<UserDefinedConversionSelector::PreparedConversion>
|
||||
SelectedConversion = ConversionSet()) {
|
||||
QualType RecordType{RD->getTypeForDecl(), 0};
|
||||
CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
|
||||
|
||||
ConversionSequence Result{RecordType, ToType};
|
||||
// The conversion from the operator call's return type to ToType was
|
||||
@ -1270,7 +1272,7 @@ tryConvertingConstructors(const TheCheck &Check, QualType FromType,
|
||||
|
||||
if (std::optional<UserDefinedConversionSelector::PreparedConversion>
|
||||
SelectedConversion = ConversionSet()) {
|
||||
QualType RecordType{RD->getTypeForDecl(), 0};
|
||||
CanQualType RecordType = RD->getASTContext().getCanonicalTagType(RD);
|
||||
|
||||
ConversionSequence Result{FromType, RecordType};
|
||||
Result.AfterFirstStandard = SelectedConversion->Seq.AfterFirstStandard;
|
||||
|
@ -69,10 +69,9 @@ void ForwardDeclarationNamespaceCheck::check(
|
||||
// struct B { friend A; };
|
||||
// \endcode
|
||||
// `A` will not be marked as "referenced" in the AST.
|
||||
if (const TypeSourceInfo *Tsi = Decl->getFriendType()) {
|
||||
QualType Desugared = Tsi->getType().getDesugaredType(*Result.Context);
|
||||
FriendTypes.insert(Desugared.getTypePtr());
|
||||
}
|
||||
if (const TypeSourceInfo *Tsi = Decl->getFriendType())
|
||||
FriendTypes.insert(
|
||||
Tsi->getType()->getCanonicalTypeUnqualified().getTypePtr());
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +118,9 @@ void ForwardDeclarationNamespaceCheck::onEndOfTranslationUnit() {
|
||||
if (CurDecl->hasDefinition() || CurDecl->isReferenced()) {
|
||||
continue; // Skip forward declarations that are used/referenced.
|
||||
}
|
||||
if (FriendTypes.contains(CurDecl->getTypeForDecl())) {
|
||||
if (FriendTypes.contains(CurDecl->getASTContext()
|
||||
.getCanonicalTagType(CurDecl)
|
||||
->getTypePtr())) {
|
||||
continue; // Skip forward declarations referenced as friend.
|
||||
}
|
||||
if (CurDecl->getLocation().isMacroID() ||
|
||||
|
@ -33,21 +33,17 @@ AST_MATCHER(QualType, isEnableIf) {
|
||||
BaseType = BaseType->getPointeeType().getTypePtr();
|
||||
}
|
||||
// Case: type parameter dependent (enable_if<is_integral<T>>).
|
||||
if (const auto *Dependent = BaseType->getAs<DependentNameType>()) {
|
||||
BaseType = Dependent->getQualifier()->getAsType();
|
||||
}
|
||||
if (const auto *Dependent = BaseType->getAs<DependentNameType>())
|
||||
BaseType = Dependent->getQualifier().getAsType();
|
||||
if (!BaseType)
|
||||
return false;
|
||||
if (CheckTemplate(BaseType->getAs<TemplateSpecializationType>()))
|
||||
return true; // Case: enable_if_t< >.
|
||||
if (const auto *Elaborated = BaseType->getAs<ElaboratedType>()) {
|
||||
if (const auto *Q = Elaborated->getQualifier())
|
||||
if (const auto *Qualifier = Q->getAsType()) {
|
||||
if (CheckTemplate(Qualifier->getAs<TemplateSpecializationType>())) {
|
||||
return true; // Case: enable_if< >::type.
|
||||
}
|
||||
}
|
||||
}
|
||||
if (const auto *TT = BaseType->getAs<TypedefType>())
|
||||
if (NestedNameSpecifier Q = TT->getQualifier();
|
||||
Q.getKind() == NestedNameSpecifier::Kind::Type)
|
||||
if (CheckTemplate(Q.getAsType()->getAs<TemplateSpecializationType>()))
|
||||
return true; // Case: enable_if< >::type.
|
||||
return false;
|
||||
}
|
||||
AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument,
|
||||
|
@ -32,13 +32,10 @@ AST_MATCHER_P(TemplateTypeParmDecl, hasUnnamedDefaultArgument,
|
||||
void IncorrectEnableIfCheck::registerMatchers(MatchFinder *Finder) {
|
||||
Finder->addMatcher(
|
||||
templateTypeParmDecl(
|
||||
hasUnnamedDefaultArgument(
|
||||
elaboratedTypeLoc(
|
||||
hasNamedTypeLoc(templateSpecializationTypeLoc(
|
||||
loc(qualType(hasDeclaration(namedDecl(
|
||||
hasName("::std::enable_if"))))))
|
||||
.bind("enable_if_specialization")))
|
||||
.bind("elaborated")))
|
||||
hasUnnamedDefaultArgument(templateSpecializationTypeLoc(
|
||||
loc(qualType(hasDeclaration(namedDecl(
|
||||
hasName("::std::enable_if"))))))
|
||||
.bind("enable_if_specialization")))
|
||||
.bind("enable_if"),
|
||||
this);
|
||||
}
|
||||
@ -46,13 +43,11 @@ void IncorrectEnableIfCheck::registerMatchers(MatchFinder *Finder) {
|
||||
void IncorrectEnableIfCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *EnableIf =
|
||||
Result.Nodes.getNodeAs<TemplateTypeParmDecl>("enable_if");
|
||||
const auto *ElaboratedLoc =
|
||||
Result.Nodes.getNodeAs<ElaboratedTypeLoc>("elaborated");
|
||||
const auto *EnableIfSpecializationLoc =
|
||||
Result.Nodes.getNodeAs<TemplateSpecializationTypeLoc>(
|
||||
"enable_if_specialization");
|
||||
|
||||
if (!EnableIf || !ElaboratedLoc || !EnableIfSpecializationLoc)
|
||||
if (!EnableIf || !EnableIfSpecializationLoc)
|
||||
return;
|
||||
|
||||
const SourceManager &SM = *Result.SourceManager;
|
||||
@ -62,8 +57,10 @@ void IncorrectEnableIfCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
auto Diag = diag(EnableIf->getBeginLoc(),
|
||||
"incorrect std::enable_if usage detected; use "
|
||||
"'typename std::enable_if<...>::type'");
|
||||
// FIXME: This should handle the enable_if specialization already having an
|
||||
// elaborated keyword.
|
||||
if (!getLangOpts().CPlusPlus20) {
|
||||
Diag << FixItHint::CreateInsertion(ElaboratedLoc->getBeginLoc(),
|
||||
Diag << FixItHint::CreateInsertion(EnableIfSpecializationLoc->getBeginLoc(),
|
||||
"typename ");
|
||||
}
|
||||
Diag << FixItHint::CreateInsertion(RAngleLoc.getLocWithOffset(1), "::type");
|
||||
|
@ -67,15 +67,15 @@ public:
|
||||
return Visit(T->getElementType().getTypePtr());
|
||||
}
|
||||
bool VisitEnumType(const EnumType *T) {
|
||||
if (isCompleteAndHasNoZeroValue(T->getDecl())) {
|
||||
if (isCompleteAndHasNoZeroValue(T->getOriginalDecl())) {
|
||||
FoundEnum = T;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool VisitRecordType(const RecordType *T) {
|
||||
const RecordDecl *RD = T->getDecl();
|
||||
if (RD->isUnion())
|
||||
const RecordDecl *RD = T->getOriginalDecl()->getDefinition();
|
||||
if (!RD || RD->isUnion())
|
||||
return false;
|
||||
auto VisitField = [this](const FieldDecl *F) {
|
||||
return Visit(F->getType().getTypePtr());
|
||||
@ -125,7 +125,7 @@ void InvalidEnumDefaultInitializationCheck::check(
|
||||
if (!Finder.Visit(InitList->getArrayFiller()->getType().getTypePtr()))
|
||||
return;
|
||||
InitExpr = InitList;
|
||||
Enum = Finder.FoundEnum->getDecl();
|
||||
Enum = Finder.FoundEnum->getOriginalDecl();
|
||||
}
|
||||
|
||||
if (!InitExpr || !Enum)
|
||||
|
@ -39,24 +39,31 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee,
|
||||
// std::move(). This will hopefully prevent erroneous replacements if the
|
||||
// code does unusual things (e.g. create an alias for std::move() in
|
||||
// another namespace).
|
||||
NestedNameSpecifier *NNS = Callee->getQualifier();
|
||||
if (!NNS) {
|
||||
NestedNameSpecifier NNS = Callee->getQualifier();
|
||||
switch (NNS.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
// Called as "move" (i.e. presumably the code had a "using std::move;").
|
||||
// We still conservatively put a "std::" in front of the forward because
|
||||
// we don't know whether the code also had a "using std::forward;".
|
||||
Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName);
|
||||
} else if (const NamespaceBaseDecl *Namespace = NNS->getAsNamespace()) {
|
||||
break;
|
||||
case NestedNameSpecifier::Kind::Namespace: {
|
||||
auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix();
|
||||
if (Namespace->getName() == "std") {
|
||||
if (!NNS->getPrefix()) {
|
||||
if (!Prefix) {
|
||||
// Called as "std::move".
|
||||
Diag << FixItHint::CreateReplacement(CallRange,
|
||||
"std::" + ForwardName);
|
||||
} else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) {
|
||||
} else if (Prefix.getKind() == NestedNameSpecifier::Kind::Global) {
|
||||
// Called as "::std::move".
|
||||
Diag << FixItHint::CreateReplacement(CallRange,
|
||||
"::std::" + ForwardName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
"suspicious usage of 'sizeof(array)/sizeof(...)';"
|
||||
" denominator differs from the size of array elements")
|
||||
<< E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
|
||||
} else if (NumTy && DenomTy && NumTy == DenomTy &&
|
||||
} else if (NumTy && DenomTy && Ctx.hasSameType(NumTy, DenomTy) &&
|
||||
!NumTy->isDependentType()) {
|
||||
// Dependent type should not be compared.
|
||||
diag(E->getOperatorLoc(),
|
||||
@ -434,7 +434,7 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
<< E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
|
||||
} else if (!WarnOnSizeOfPointer) {
|
||||
// When 'WarnOnSizeOfPointer' is enabled, these messages become redundant:
|
||||
if (PointedTy && DenomTy && PointedTy == DenomTy) {
|
||||
if (PointedTy && DenomTy && Ctx.hasSameType(PointedTy, DenomTy)) {
|
||||
diag(E->getOperatorLoc(),
|
||||
"suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer "
|
||||
"is divided by size of pointed type")
|
||||
@ -463,7 +463,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *SizeOfExpr =
|
||||
Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-mul-expr");
|
||||
|
||||
if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
|
||||
if (Ctx.hasSameType(LPtrTy, RPtrTy) &&
|
||||
Ctx.hasSameType(LPtrTy, SizeofArgTy)) {
|
||||
diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "
|
||||
"pointer arithmetic")
|
||||
<< SizeOfExpr->getSourceRange() << E->getOperatorLoc()
|
||||
@ -477,7 +478,8 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *SizeOfExpr =
|
||||
Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-div-expr");
|
||||
|
||||
if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
|
||||
if (Ctx.hasSameType(LPtrTy, RPtrTy) &&
|
||||
Ctx.hasSameType(LPtrTy, SizeofArgTy)) {
|
||||
diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "
|
||||
"pointer arithmetic")
|
||||
<< SizeOfExpr->getSourceRange() << E->getOperatorLoc()
|
||||
|
@ -23,9 +23,9 @@ void NoSuspendWithLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
||||
}
|
||||
|
||||
void NoSuspendWithLockCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto LockType = elaboratedType(namesType(templateSpecializationType(
|
||||
auto LockType = templateSpecializationType(
|
||||
hasDeclaration(namedDecl(matchers::matchesAnyListedName(
|
||||
utils::options::parseStringList(LockGuards)))))));
|
||||
utils::options::parseStringList(LockGuards)))));
|
||||
|
||||
StatementMatcher Lock =
|
||||
declStmt(has(varDecl(hasType(LockType)).bind("lock-decl")))
|
||||
|
@ -190,7 +190,7 @@ struct InitializerInsertion {
|
||||
// Convenience utility to get a RecordDecl from a QualType.
|
||||
const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
|
||||
if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
|
||||
return RT->getDecl();
|
||||
return RT->getOriginalDecl();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ void SlicingCheck::diagnoseSlicedOverriddenMethods(
|
||||
for (const auto &Base : DerivedDecl.bases()) {
|
||||
if (const auto *BaseRecordType = Base.getType()->getAs<RecordType>()) {
|
||||
if (const auto *BaseRecord = cast_or_null<CXXRecordDecl>(
|
||||
BaseRecordType->getDecl()->getDefinition()))
|
||||
BaseRecordType->getOriginalDecl()->getDefinition()))
|
||||
diagnoseSlicedOverriddenMethods(Call, *BaseRecord, BaseDecl);
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ bool MultipleInheritanceCheck::isInterface(const CXXRecordDecl *Node) {
|
||||
const auto *Ty = I.getType()->getAs<RecordType>();
|
||||
if (!Ty)
|
||||
continue;
|
||||
const RecordDecl *D = Ty->getDecl()->getDefinition();
|
||||
const RecordDecl *D = Ty->getOriginalDecl()->getDefinition();
|
||||
if (!D)
|
||||
continue;
|
||||
const auto *Base = cast<CXXRecordDecl>(D);
|
||||
@ -106,7 +106,8 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *Ty = I.getType()->getAs<RecordType>();
|
||||
if (!Ty)
|
||||
continue;
|
||||
const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
|
||||
const auto *Base =
|
||||
cast<CXXRecordDecl>(Ty->getOriginalDecl()->getDefinition());
|
||||
if (!isInterface(Base))
|
||||
NumConcrete++;
|
||||
}
|
||||
@ -117,7 +118,8 @@ void MultipleInheritanceCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *Ty = V.getType()->getAs<RecordType>();
|
||||
if (!Ty)
|
||||
continue;
|
||||
const auto *Base = cast<CXXRecordDecl>(Ty->getDecl()->getDefinition());
|
||||
const auto *Base =
|
||||
cast<CXXRecordDecl>(Ty->getOriginalDecl()->getDefinition());
|
||||
if (!isInterface(Base))
|
||||
NumConcrete++;
|
||||
}
|
||||
|
@ -89,6 +89,30 @@ static StringRef getDestTypeString(const SourceManager &SM,
|
||||
SM, LangOpts);
|
||||
}
|
||||
|
||||
static bool sameTypeAsWritten(QualType X, QualType Y) {
|
||||
if (X.getCanonicalType() != Y.getCanonicalType())
|
||||
return false;
|
||||
|
||||
auto TC = X->getTypeClass();
|
||||
if (TC != Y->getTypeClass())
|
||||
return false;
|
||||
|
||||
switch (TC) {
|
||||
case Type::Typedef:
|
||||
return declaresSameEntity(cast<TypedefType>(X)->getDecl(),
|
||||
cast<TypedefType>(Y)->getDecl());
|
||||
case Type::Pointer:
|
||||
return sameTypeAsWritten(cast<PointerType>(X)->getPointeeType(),
|
||||
cast<PointerType>(Y)->getPointeeType());
|
||||
case Type::RValueReference:
|
||||
case Type::LValueReference:
|
||||
return sameTypeAsWritten(cast<ReferenceType>(X)->getPointeeType(),
|
||||
cast<ReferenceType>(Y)->getPointeeType());
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
|
||||
|
||||
@ -128,12 +152,7 @@ void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
// case of overloaded functions, so detection of redundant casts is trickier
|
||||
// in this case. Don't emit "redundant cast" warnings for function
|
||||
// pointer/reference types.
|
||||
QualType Src = SourceTypeAsWritten, Dst = DestTypeAsWritten;
|
||||
if (const auto *ElTy = dyn_cast<ElaboratedType>(Src))
|
||||
Src = ElTy->getNamedType();
|
||||
if (const auto *ElTy = dyn_cast<ElaboratedType>(Dst))
|
||||
Dst = ElTy->getNamedType();
|
||||
if (Src == Dst) {
|
||||
if (sameTypeAsWritten(SourceTypeAsWritten, DestTypeAsWritten)) {
|
||||
diag(CastExpr->getBeginLoc(), "redundant cast to the same type")
|
||||
<< FixItHint::CreateRemoval(ReplaceRange);
|
||||
return;
|
||||
|
@ -72,7 +72,7 @@ static bool isStdInitializerList(QualType Type) {
|
||||
}
|
||||
if (const auto *RT = Type->getAs<RecordType>()) {
|
||||
if (const auto *Specialization =
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
|
||||
dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl()))
|
||||
return declIsStdInitializerList(Specialization->getSpecializedTemplate());
|
||||
}
|
||||
return false;
|
||||
|
@ -257,8 +257,13 @@ getAliasNameRange(const MatchFinder::MatchResult &Result) {
|
||||
return CharSourceRange::getTokenRange(
|
||||
Using->getNameInfo().getSourceRange());
|
||||
}
|
||||
return CharSourceRange::getTokenRange(
|
||||
Result.Nodes.getNodeAs<TypeLoc>("typeloc")->getSourceRange());
|
||||
TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("typeloc");
|
||||
if (auto QTL = TL.getAs<QualifiedTypeLoc>())
|
||||
TL = QTL.getUnqualifiedLoc();
|
||||
|
||||
if (auto TTL = TL.getAs<TypedefTypeLoc>())
|
||||
return CharSourceRange::getTokenRange(TTL.getNameLoc());
|
||||
return CharSourceRange::getTokenRange(TL.castAs<UsingTypeLoc>().getNameLoc());
|
||||
}
|
||||
|
||||
void UpgradeGoogletestCaseCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
|
@ -98,11 +98,12 @@ void ConstCorrectnessCheck::registerMatchers(MatchFinder *Finder) {
|
||||
hasType(referenceType(pointee(hasCanonicalType(templateTypeParmType())))),
|
||||
hasType(referenceType(pointee(substTemplateTypeParmType()))));
|
||||
|
||||
const auto AllowedType = hasType(qualType(anyOf(
|
||||
hasDeclaration(namedDecl(matchers::matchesAnyListedName(AllowedTypes))),
|
||||
references(namedDecl(matchers::matchesAnyListedName(AllowedTypes))),
|
||||
pointerType(pointee(hasDeclaration(
|
||||
namedDecl(matchers::matchesAnyListedName(AllowedTypes))))))));
|
||||
auto AllowedTypeDecl = namedDecl(
|
||||
anyOf(matchers::matchesAnyListedName(AllowedTypes), usingShadowDecl()));
|
||||
|
||||
const auto AllowedType = hasType(qualType(
|
||||
anyOf(hasDeclaration(AllowedTypeDecl), references(AllowedTypeDecl),
|
||||
pointerType(pointee(hasDeclaration(AllowedTypeDecl))))));
|
||||
|
||||
const auto AutoTemplateType = varDecl(
|
||||
anyOf(hasType(autoType()), hasType(referenceType(pointee(autoType()))),
|
||||
|
@ -19,13 +19,13 @@ void MisplacedConstCheck::registerMatchers(MatchFinder *Finder) {
|
||||
pointee(anyOf(isConstQualified(), ignoringParens(functionType()))))));
|
||||
|
||||
Finder->addMatcher(
|
||||
valueDecl(hasType(qualType(
|
||||
isConstQualified(),
|
||||
elaboratedType(namesType(typedefType(hasDeclaration(
|
||||
anyOf(typedefDecl(NonConstAndNonFunctionPointerType)
|
||||
.bind("typedef"),
|
||||
typeAliasDecl(NonConstAndNonFunctionPointerType)
|
||||
.bind("typeAlias")))))))))
|
||||
valueDecl(
|
||||
hasType(qualType(isConstQualified(),
|
||||
typedefType(hasDeclaration(anyOf(
|
||||
typedefDecl(NonConstAndNonFunctionPointerType)
|
||||
.bind("typedef"),
|
||||
typeAliasDecl(NonConstAndNonFunctionPointerType)
|
||||
.bind("typeAlias")))))))
|
||||
.bind("decl"),
|
||||
this);
|
||||
}
|
||||
|
@ -45,14 +45,6 @@ static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) {
|
||||
return Value < Result;
|
||||
}
|
||||
|
||||
static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left,
|
||||
const NestedNameSpecifier *Right) {
|
||||
llvm::FoldingSetNodeID LeftID, RightID;
|
||||
Left->Profile(LeftID);
|
||||
Right->Profile(RightID);
|
||||
return LeftID == RightID;
|
||||
}
|
||||
|
||||
static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
|
||||
if (!Left || !Right)
|
||||
return !Left && !Right;
|
||||
@ -104,9 +96,8 @@ static bool areEquivalentExpr(const Expr *Left, const Expr *Right) {
|
||||
if (cast<DependentScopeDeclRefExpr>(Left)->getDeclName() !=
|
||||
cast<DependentScopeDeclRefExpr>(Right)->getDeclName())
|
||||
return false;
|
||||
return areEquivalentNameSpecifier(
|
||||
cast<DependentScopeDeclRefExpr>(Left)->getQualifier(),
|
||||
cast<DependentScopeDeclRefExpr>(Right)->getQualifier());
|
||||
return cast<DependentScopeDeclRefExpr>(Left)->getQualifier() ==
|
||||
cast<DependentScopeDeclRefExpr>(Right)->getQualifier();
|
||||
case Stmt::DeclRefExprClass:
|
||||
return cast<DeclRefExpr>(Left)->getDecl() ==
|
||||
cast<DeclRefExpr>(Right)->getDecl();
|
||||
|
@ -35,12 +35,12 @@ void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
}
|
||||
|
||||
if (const auto *NestedName =
|
||||
Result.Nodes.getNodeAs<NestedNameSpecifier>("nns")) {
|
||||
if (const auto *AliasDecl = dyn_cast_if_present<NamespaceAliasDecl>(
|
||||
NestedName->getAsNamespace())) {
|
||||
Result.Nodes.getNodeAs<NestedNameSpecifier>("nns");
|
||||
NestedName &&
|
||||
NestedName->getKind() == NestedNameSpecifier::Kind::Namespace)
|
||||
if (const auto *AliasDecl = dyn_cast<NamespaceAliasDecl>(
|
||||
NestedName->getAsNamespaceAndPrefix().Namespace))
|
||||
FoundDecls[AliasDecl] = CharSourceRange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UnusedAliasDeclsCheck::onEndOfTranslationUnit() {
|
||||
|
@ -71,11 +71,7 @@ void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) {
|
||||
templateArgument().bind("used")))),
|
||||
this);
|
||||
Finder->addMatcher(userDefinedLiteral().bind("used"), this);
|
||||
Finder->addMatcher(
|
||||
loc(elaboratedType(unless(hasQualifier(nestedNameSpecifier())),
|
||||
hasUnqualifiedDesugaredType(
|
||||
type(asTagDecl(tagDecl().bind("used")))))),
|
||||
this);
|
||||
Finder->addMatcher(loc(asTagDecl(tagDecl().bind("used"))), this);
|
||||
// Cases where we can identify the UsingShadowDecl directly, rather than
|
||||
// just its target.
|
||||
// FIXME: cover more cases in this way, as the AST supports it.
|
||||
@ -136,7 +132,7 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
}
|
||||
if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
|
||||
if (const auto *ET = ECD->getType()->getAs<EnumType>())
|
||||
removeFromFoundDecls(ET->getDecl());
|
||||
removeFromFoundDecls(ET->getOriginalDecl());
|
||||
}
|
||||
};
|
||||
// We rely on the fact that the clang AST is walked in order, usages are only
|
||||
|
@ -29,8 +29,7 @@ static std::optional<const char *> getReplacementType(StringRef Type) {
|
||||
|
||||
void DeprecatedIosBaseAliasesCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto IoStateDecl = typedefDecl(hasAnyName(DeprecatedTypes)).bind("TypeDecl");
|
||||
auto IoStateType =
|
||||
qualType(hasDeclaration(IoStateDecl), unless(elaboratedType()));
|
||||
auto IoStateType = typedefType(hasDeclaration(IoStateDecl));
|
||||
|
||||
Finder->addMatcher(typeLoc(loc(IoStateType)).bind("TypeLoc"), this);
|
||||
}
|
||||
@ -43,12 +42,14 @@ void DeprecatedIosBaseAliasesCheck::check(
|
||||
StringRef TypeName = Typedef->getName();
|
||||
auto Replacement = getReplacementType(TypeName);
|
||||
|
||||
const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("TypeLoc");
|
||||
SourceLocation IoStateLoc = TL->getBeginLoc();
|
||||
TypeLoc TL = *Result.Nodes.getNodeAs<TypeLoc>("TypeLoc");
|
||||
if (auto QTL = TL.getAs<QualifiedTypeLoc>())
|
||||
TL = QTL.getUnqualifiedLoc();
|
||||
|
||||
SourceLocation IoStateLoc = TL.castAs<TypedefTypeLoc>().getNameLoc();
|
||||
// Do not generate fixits for matches depending on template arguments and
|
||||
// macro expansions.
|
||||
bool Fix = Replacement && !TL->getType()->isDependentType();
|
||||
bool Fix = Replacement && !TL.getType()->isDependentType();
|
||||
if (IoStateLoc.isMacroID()) {
|
||||
IoStateLoc = SM.getSpellingLoc(IoStateLoc);
|
||||
Fix = false;
|
||||
|
@ -77,8 +77,7 @@ AST_MATCHER_P(CXXRecordDecl, isMoveConstructibleInBoundCXXRecordDecl, StringRef,
|
||||
|
||||
static TypeMatcher notTemplateSpecConstRefType() {
|
||||
return lValueReferenceType(
|
||||
pointee(unless(elaboratedType(namesType(templateSpecializationType()))),
|
||||
isConstQualified()));
|
||||
pointee(unless(templateSpecializationType()), isConstQualified()));
|
||||
}
|
||||
|
||||
static TypeMatcher nonConstValueType() {
|
||||
|
@ -48,7 +48,7 @@ void ReplaceAutoPtrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
||||
|
||||
void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto AutoPtrDecl = recordDecl(hasName("auto_ptr"), isInStdNamespace());
|
||||
auto AutoPtrType = qualType(hasDeclaration(AutoPtrDecl));
|
||||
auto AutoPtrType = hasCanonicalType(recordType(hasDeclaration(AutoPtrDecl)));
|
||||
|
||||
// std::auto_ptr<int> a;
|
||||
// ^~~~~~~~~~~~~
|
||||
@ -58,11 +58,7 @@ void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) {
|
||||
//
|
||||
// std::auto_ptr<int> fn(std::auto_ptr<int>);
|
||||
// ^~~~~~~~~~~~~ ^~~~~~~~~~~~~
|
||||
Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType,
|
||||
// Skip elaboratedType() as the named
|
||||
// type will match soon thereafter.
|
||||
unless(elaboratedType()))))
|
||||
.bind(AutoPtrTokenId),
|
||||
Finder->addMatcher(typeLoc(loc(qualType(AutoPtrType))).bind(AutoPtrTokenId),
|
||||
this);
|
||||
|
||||
// using std::auto_ptr;
|
||||
@ -118,10 +114,13 @@ void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
}
|
||||
|
||||
SourceLocation AutoPtrLoc;
|
||||
if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
|
||||
if (const auto *PTL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
|
||||
auto TL = *PTL;
|
||||
if (auto QTL = TL.getAs<QualifiedTypeLoc>())
|
||||
TL = QTL.getUnqualifiedLoc();
|
||||
// std::auto_ptr<int> i;
|
||||
// ^
|
||||
if (auto Loc = TL->getAs<TemplateSpecializationTypeLoc>())
|
||||
if (auto Loc = TL.getAs<TemplateSpecializationTypeLoc>())
|
||||
AutoPtrLoc = Loc.getTemplateNameLoc();
|
||||
} else if (const auto *D =
|
||||
Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
|
||||
|
@ -168,19 +168,6 @@ static DeclarationName getName(const DeclRefExpr &D) {
|
||||
return D.getDecl()->getDeclName();
|
||||
}
|
||||
|
||||
static bool isNamedType(const ElaboratedTypeLoc &ETL) {
|
||||
if (const auto *TFT =
|
||||
ETL.getNamedTypeLoc().getTypePtr()->getAs<TypedefType>()) {
|
||||
const TypedefNameDecl *Decl = TFT->getDecl();
|
||||
return Decl->getDeclName().isIdentifier() && Decl->getName() == "type";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isNamedType(const DependentNameTypeLoc &DTL) {
|
||||
return DTL.getTypePtr()->getIdentifier()->getName() == "type";
|
||||
}
|
||||
|
||||
namespace {
|
||||
AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES(
|
||||
DeclRefExpr, DependentScopeDeclRefExpr)) {
|
||||
@ -188,10 +175,14 @@ AST_POLYMORPHIC_MATCHER(isValue, AST_POLYMORPHIC_SUPPORTED_TYPES(
|
||||
return Ident && Ident->isStr("value");
|
||||
}
|
||||
|
||||
AST_POLYMORPHIC_MATCHER(isType,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(ElaboratedTypeLoc,
|
||||
DependentNameTypeLoc)) {
|
||||
return Node.getBeginLoc().isValid() && isNamedType(Node);
|
||||
AST_MATCHER(TypeLoc, isType) {
|
||||
if (auto TL = Node.getAs<TypedefTypeLoc>()) {
|
||||
const auto *TD = TL.getDecl();
|
||||
return TD->getDeclName().isIdentifier() && TD->getName() == "type";
|
||||
}
|
||||
if (auto TL = Node.getAs<DependentNameTypeLoc>())
|
||||
return TL.getTypePtr()->getIdentifier()->getName() == "type";
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -214,10 +205,7 @@ void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) {
|
||||
.bind(Bind),
|
||||
this);
|
||||
}
|
||||
Finder->addMatcher(mapAnyOf(elaboratedTypeLoc, dependentNameTypeLoc)
|
||||
.with(isType())
|
||||
.bind(Bind),
|
||||
this);
|
||||
Finder->addMatcher(typeLoc(isType()).bind(Bind), this);
|
||||
}
|
||||
|
||||
static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,
|
||||
@ -226,14 +214,11 @@ static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,
|
||||
Set.contains(ND->getName());
|
||||
}
|
||||
|
||||
static bool checkTemplatedDecl(const NestedNameSpecifier *NNS,
|
||||
static bool checkTemplatedDecl(NestedNameSpecifier NNS,
|
||||
const llvm::StringSet<> &Set) {
|
||||
if (!NNS)
|
||||
if (NNS.getKind() != NestedNameSpecifier::Kind::Type)
|
||||
return false;
|
||||
const Type *NNST = NNS->getAsType();
|
||||
if (!NNST)
|
||||
return false;
|
||||
const auto *TST = NNST->getAs<TemplateSpecializationType>();
|
||||
const auto *TST = NNS.getAsType()->getAs<TemplateSpecializationType>();
|
||||
if (!TST)
|
||||
return false;
|
||||
if (const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) {
|
||||
@ -250,8 +235,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
auto EmitValueWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc,
|
||||
SourceLocation EndLoc) {
|
||||
SourceLocation TemplateNameEndLoc;
|
||||
if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
|
||||
!TSTL.isNull())
|
||||
if (auto TSTL =
|
||||
QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>())
|
||||
TemplateNameEndLoc = Lexer::getLocForEndOfToken(
|
||||
TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
|
||||
Result.Context->getLangOpts());
|
||||
@ -274,8 +259,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
SourceLocation EndLoc,
|
||||
SourceLocation TypenameLoc) {
|
||||
SourceLocation TemplateNameEndLoc;
|
||||
if (auto TSTL = QualLoc.getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
|
||||
!TSTL.isNull())
|
||||
if (auto TSTL =
|
||||
QualLoc.getAsTypeLoc().getAs<TemplateSpecializationTypeLoc>())
|
||||
TemplateNameEndLoc = Lexer::getLocForEndOfToken(
|
||||
TSTL.getTemplateNameLoc(), 0, *Result.SourceManager,
|
||||
Result.Context->getLangOpts());
|
||||
@ -301,23 +286,21 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
if (!DRE->hasQualifier())
|
||||
return;
|
||||
if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
|
||||
DRE->getQualifier()->getAsRecordDecl())) {
|
||||
DRE->getQualifier().getAsRecordDecl())) {
|
||||
if (isNamedDeclInStdTraitsSet(CTSD, ValueTraits))
|
||||
EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto *ETL = Result.Nodes.getNodeAs<ElaboratedTypeLoc>(Bind)) {
|
||||
const NestedNameSpecifierLoc QualLoc = ETL->getQualifierLoc();
|
||||
const auto *NNS = QualLoc.getNestedNameSpecifier();
|
||||
if (!NNS)
|
||||
return;
|
||||
if (const auto *TL = Result.Nodes.getNodeAs<TypedefTypeLoc>(Bind)) {
|
||||
const NestedNameSpecifierLoc QualLoc = TL->getQualifierLoc();
|
||||
NestedNameSpecifier NNS = QualLoc.getNestedNameSpecifier();
|
||||
if (const auto *CTSD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
|
||||
NNS->getAsRecordDecl())) {
|
||||
NNS.getAsRecordDecl())) {
|
||||
if (isNamedDeclInStdTraitsSet(CTSD, TypeTraits))
|
||||
EmitTypeWarning(ETL->getQualifierLoc(), ETL->getEndLoc(),
|
||||
ETL->getElaboratedKeywordLoc());
|
||||
EmitTypeWarning(TL->getQualifierLoc(), TL->getEndLoc(),
|
||||
TL->getElaboratedKeywordLoc());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -186,16 +186,14 @@ TypeMatcher nestedIterator() {
|
||||
/// declarations and which name standard iterators for standard containers.
|
||||
TypeMatcher iteratorFromUsingDeclaration() {
|
||||
auto HasIteratorDecl = hasDeclaration(namedDecl(hasStdIteratorName()));
|
||||
// Types resulting from using declarations are represented by elaboratedType.
|
||||
return elaboratedType(
|
||||
// Unwrap the nested name specifier to test for one of the standard
|
||||
// containers.
|
||||
hasQualifier(specifiesType(templateSpecializationType(hasDeclaration(
|
||||
namedDecl(hasStdContainerName(), isInStdNamespace()))))),
|
||||
// the named type is what comes after the final '::' in the type. It
|
||||
// should name one of the standard iterator names.
|
||||
namesType(
|
||||
anyOf(typedefType(HasIteratorDecl), recordType(HasIteratorDecl))));
|
||||
// Unwrap the nested name specifier to test for one of the standard
|
||||
// containers.
|
||||
auto Qualifier = hasQualifier(specifiesType(templateSpecializationType(
|
||||
hasDeclaration(namedDecl(hasStdContainerName(), isInStdNamespace())))));
|
||||
// the named type is what comes after the final '::' in the type. It should
|
||||
// name one of the standard iterator names.
|
||||
return anyOf(typedefType(HasIteratorDecl, Qualifier),
|
||||
recordType(HasIteratorDecl, Qualifier));
|
||||
}
|
||||
|
||||
/// This matcher returns declaration statements that contain variable
|
||||
|
@ -60,9 +60,11 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
|
||||
Keyword != ElaboratedTypeKeyword::None)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
TheType = Dep.getQualifierLoc().getTypeLoc();
|
||||
TheType = Dep.getQualifierLoc().getAsTypeLoc();
|
||||
if (TheType.isNull())
|
||||
return std::nullopt;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (const auto SpecializationLoc =
|
||||
@ -89,9 +91,6 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) {
|
||||
|
||||
static std::optional<TemplateSpecializationTypeLoc>
|
||||
matchEnableIfSpecializationImplTrait(TypeLoc TheType) {
|
||||
if (const auto Elaborated = TheType.getAs<ElaboratedTypeLoc>())
|
||||
TheType = Elaborated.getNamedTypeLoc();
|
||||
|
||||
if (const auto SpecializationLoc =
|
||||
TheType.getAs<TemplateSpecializationTypeLoc>()) {
|
||||
|
||||
|
@ -164,10 +164,10 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto CallEmplacy = cxxMemberCallExpr(
|
||||
hasDeclaration(
|
||||
functionDecl(hasAnyNameIgnoringTemplates(EmplacyFunctions))),
|
||||
on(hasTypeOrPointeeType(hasCanonicalType(hasDeclaration(
|
||||
has(typedefNameDecl(hasName("value_type"),
|
||||
hasType(type(hasUnqualifiedDesugaredType(
|
||||
recordType().bind("value_type")))))))))));
|
||||
on(hasTypeOrPointeeType(
|
||||
hasCanonicalType(hasDeclaration(has(typedefNameDecl(
|
||||
hasName("value_type"),
|
||||
hasType(hasCanonicalType(recordType().bind("value_type"))))))))));
|
||||
|
||||
// We can't replace push_backs of smart pointer because
|
||||
// if emplacement fails (f.e. bad_alloc in vector) we will have leak of
|
||||
@ -241,17 +241,16 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
|
||||
|
||||
auto HasConstructExprWithValueTypeType =
|
||||
has(ignoringImplicit(cxxConstructExpr(
|
||||
SoughtConstructExpr, hasType(type(hasUnqualifiedDesugaredType(
|
||||
type(equalsBoundNode("value_type"))))))));
|
||||
SoughtConstructExpr,
|
||||
hasType(hasCanonicalType(type(equalsBoundNode("value_type")))))));
|
||||
|
||||
auto HasBracedInitListWithValueTypeType =
|
||||
anyOf(allOf(HasConstructInitListExpr,
|
||||
has(initListExpr(hasType(type(hasUnqualifiedDesugaredType(
|
||||
type(equalsBoundNode("value_type")))))))),
|
||||
has(cxxBindTemporaryExpr(
|
||||
HasConstructInitListExpr,
|
||||
has(initListExpr(hasType(type(hasUnqualifiedDesugaredType(
|
||||
type(equalsBoundNode("value_type"))))))))));
|
||||
auto HasBracedInitListWithValueTypeType = anyOf(
|
||||
allOf(HasConstructInitListExpr,
|
||||
has(initListExpr(hasType(
|
||||
hasCanonicalType(type(equalsBoundNode("value_type"))))))),
|
||||
has(cxxBindTemporaryExpr(HasConstructInitListExpr,
|
||||
has(initListExpr(hasType(hasCanonicalType(
|
||||
type(equalsBoundNode("value_type")))))))));
|
||||
|
||||
auto HasConstructExprWithValueTypeTypeAsLastArgument = hasLastArgument(
|
||||
materializeTemporaryExpr(
|
||||
@ -289,19 +288,17 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) {
|
||||
this);
|
||||
|
||||
Finder->addMatcher(
|
||||
traverse(
|
||||
TK_AsIs,
|
||||
cxxMemberCallExpr(
|
||||
CallEmplacy,
|
||||
on(hasType(cxxRecordDecl(has(typedefNameDecl(
|
||||
hasName("value_type"),
|
||||
hasType(type(
|
||||
hasUnqualifiedDesugaredType(recordType(hasDeclaration(
|
||||
cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
|
||||
TupleTypes.begin(), TupleTypes.end()))))))))))))),
|
||||
has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
|
||||
unless(isInTemplateInstantiation()))
|
||||
.bind("emplacy_call")),
|
||||
traverse(TK_AsIs,
|
||||
cxxMemberCallExpr(
|
||||
CallEmplacy,
|
||||
on(hasType(cxxRecordDecl(has(typedefNameDecl(
|
||||
hasName("value_type"),
|
||||
hasType(hasCanonicalType(recordType(hasDeclaration(
|
||||
cxxRecordDecl(hasAnyName(SmallVector<StringRef, 2>(
|
||||
TupleTypes.begin(), TupleTypes.end())))))))))))),
|
||||
has(MakeTuple), hasSameNumArgsAsDeclNumParams(),
|
||||
unless(isInTemplateInstantiation()))
|
||||
.bind("emplacy_call")),
|
||||
this);
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ static bool isLockGuardDecl(const NamedDecl *Decl) {
|
||||
|
||||
static bool isLockGuard(const QualType &Type) {
|
||||
if (const auto *Record = Type->getAs<RecordType>())
|
||||
if (const RecordDecl *Decl = Record->getDecl())
|
||||
if (const RecordDecl *Decl = Record->getOriginalDecl())
|
||||
return isLockGuardDecl(Decl);
|
||||
|
||||
if (const auto *TemplateSpecType = Type->getAs<TemplateSpecializationType>())
|
||||
@ -89,17 +89,6 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
|
||||
return LockGuardGroups;
|
||||
}
|
||||
|
||||
static TemplateSpecializationTypeLoc
|
||||
getTemplateLockGuardTypeLoc(const TypeSourceInfo *SourceInfo) {
|
||||
const TypeLoc Loc = SourceInfo->getTypeLoc();
|
||||
|
||||
const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>();
|
||||
if (!ElaboratedLoc)
|
||||
return {};
|
||||
|
||||
return ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>();
|
||||
}
|
||||
|
||||
// Find the exact source range of the 'lock_guard' token
|
||||
static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) {
|
||||
const TypeLoc LockGuardTypeLoc = SourceInfo->getTypeLoc();
|
||||
@ -110,7 +99,7 @@ static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) {
|
||||
// Find the exact source range of the 'lock_guard' name token
|
||||
static SourceRange getLockGuardNameRange(const TypeSourceInfo *SourceInfo) {
|
||||
const TemplateSpecializationTypeLoc TemplateLoc =
|
||||
getTemplateLockGuardTypeLoc(SourceInfo);
|
||||
SourceInfo->getTypeLoc().getAs<TemplateSpecializationTypeLoc>();
|
||||
if (!TemplateLoc)
|
||||
return {};
|
||||
|
||||
@ -136,11 +125,11 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
|
||||
const auto LockGuardClassDecl =
|
||||
namedDecl(hasName("lock_guard"), isInStdNamespace());
|
||||
|
||||
const auto LockGuardType = qualType(anyOf(
|
||||
hasUnqualifiedDesugaredType(
|
||||
recordType(hasDeclaration(LockGuardClassDecl))),
|
||||
elaboratedType(namesType(hasUnqualifiedDesugaredType(
|
||||
templateSpecializationType(hasDeclaration(LockGuardClassDecl)))))));
|
||||
const auto LockGuardType =
|
||||
qualType(anyOf(hasUnqualifiedDesugaredType(
|
||||
recordType(hasDeclaration(LockGuardClassDecl))),
|
||||
hasUnqualifiedDesugaredType(templateSpecializationType(
|
||||
hasDeclaration(LockGuardClassDecl)))));
|
||||
|
||||
const auto LockVarDecl = varDecl(hasType(LockGuardType));
|
||||
|
||||
@ -165,18 +154,16 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
|
||||
if (WarnOnUsingAndTypedef) {
|
||||
// Match 'typedef std::lock_guard<std::mutex> Lock'
|
||||
Finder->addMatcher(typedefDecl(unless(isExpansionInSystemHeader()),
|
||||
hasUnderlyingType(LockGuardType))
|
||||
hasType(hasUnderlyingType(LockGuardType)))
|
||||
.bind("lock-guard-typedef"),
|
||||
this);
|
||||
|
||||
// Match 'using Lock = std::lock_guard<std::mutex>'
|
||||
Finder->addMatcher(
|
||||
typeAliasDecl(
|
||||
unless(isExpansionInSystemHeader()),
|
||||
hasType(elaboratedType(namesType(templateSpecializationType(
|
||||
hasDeclaration(LockGuardClassDecl))))))
|
||||
.bind("lock-guard-using-alias"),
|
||||
this);
|
||||
Finder->addMatcher(typeAliasDecl(unless(isExpansionInSystemHeader()),
|
||||
hasType(templateSpecializationType(
|
||||
hasDeclaration(LockGuardClassDecl))))
|
||||
.bind("lock-guard-using-alias"),
|
||||
this);
|
||||
|
||||
// Match 'using std::lock_guard'
|
||||
Finder->addMatcher(
|
||||
@ -288,8 +275,8 @@ void UseScopedLockCheck::diagOnSourceInfo(
|
||||
const ast_matchers::MatchFinder::MatchResult &Result) {
|
||||
const TypeLoc TL = LockGuardSourceInfo->getTypeLoc();
|
||||
|
||||
if (const auto ElaboratedTL = TL.getAs<ElaboratedTypeLoc>()) {
|
||||
auto Diag = diag(ElaboratedTL.getBeginLoc(), UseScopedLockMessage);
|
||||
if (const auto TTL = TL.getAs<TemplateSpecializationTypeLoc>()) {
|
||||
auto Diag = diag(TTL.getBeginLoc(), UseScopedLockMessage);
|
||||
|
||||
const SourceRange LockGuardRange =
|
||||
getLockGuardNameRange(LockGuardSourceInfo);
|
||||
|
@ -64,66 +64,65 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TraverseTypeLoc(TypeLoc TL, bool Elaborated = false) {
|
||||
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
|
||||
if (TL.isNull())
|
||||
return true;
|
||||
|
||||
if (!Elaborated) {
|
||||
switch (TL.getTypeLocClass()) {
|
||||
case TypeLoc::Record:
|
||||
if (visitUnqualName(
|
||||
TL.getAs<RecordTypeLoc>().getTypePtr()->getDecl()->getName()))
|
||||
return false;
|
||||
switch (TL.getTypeLocClass()) {
|
||||
case TypeLoc::InjectedClassName:
|
||||
case TypeLoc::Record:
|
||||
case TypeLoc::Enum: {
|
||||
auto TTL = TL.getAs<TagTypeLoc>();
|
||||
const auto *T = TTL.getTypePtr();
|
||||
if (T->getKeyword() != ElaboratedTypeKeyword::None ||
|
||||
TTL.getQualifierLoc())
|
||||
break;
|
||||
case TypeLoc::Enum:
|
||||
if (visitUnqualName(
|
||||
TL.getAs<EnumTypeLoc>().getTypePtr()->getDecl()->getName()))
|
||||
return false;
|
||||
if (visitUnqualName(T->getOriginalDecl()->getName()))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case TypeLoc::TemplateSpecialization: {
|
||||
auto TTL = TL.getAs<TemplateSpecializationTypeLoc>();
|
||||
const auto *T = TTL.getTypePtr();
|
||||
if (T->getKeyword() != ElaboratedTypeKeyword::None ||
|
||||
TTL.getQualifierLoc())
|
||||
break;
|
||||
case TypeLoc::TemplateSpecialization:
|
||||
if (visitUnqualName(TL.getAs<TemplateSpecializationTypeLoc>()
|
||||
.getTypePtr()
|
||||
->getTemplateName()
|
||||
.getAsTemplateDecl()
|
||||
->getName()))
|
||||
return false;
|
||||
if (visitUnqualName(T->getTemplateName().getAsTemplateDecl()->getName()))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case TypeLoc::Typedef: {
|
||||
auto TTL = TL.getAs<TypedefTypeLoc>();
|
||||
const auto *T = TTL.getTypePtr();
|
||||
if (T->getKeyword() != ElaboratedTypeKeyword::None ||
|
||||
TTL.getQualifierLoc())
|
||||
break;
|
||||
case TypeLoc::Typedef:
|
||||
if (visitUnqualName(
|
||||
TL.getAs<TypedefTypeLoc>().getTypePtr()->getDecl()->getName()))
|
||||
return false;
|
||||
if (visitUnqualName(T->getDecl()->getName()))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case TypeLoc::Using: {
|
||||
auto TTL = TL.getAs<UsingTypeLoc>();
|
||||
const auto *T = TTL.getTypePtr();
|
||||
if (T->getKeyword() != ElaboratedTypeKeyword::None ||
|
||||
TTL.getQualifierLoc())
|
||||
break;
|
||||
case TypeLoc::Using:
|
||||
if (visitUnqualName(TL.getAs<UsingTypeLoc>()
|
||||
.getTypePtr()
|
||||
->getFoundDecl()
|
||||
->getName()))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (visitUnqualName(T->getDecl()->getName()))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc(TL);
|
||||
return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc(
|
||||
TL, TraverseQualifier);
|
||||
}
|
||||
|
||||
// Replace the base method in order to call our own
|
||||
// TraverseTypeLoc().
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
||||
return TraverseTypeLoc(TL.getUnqualifiedLoc());
|
||||
}
|
||||
|
||||
// Replace the base version to inform TraverseTypeLoc that the type is
|
||||
// elaborated.
|
||||
bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
||||
if (TL.getQualifierLoc() &&
|
||||
!TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()))
|
||||
return false;
|
||||
const auto *T = TL.getTypePtr();
|
||||
return TraverseTypeLoc(TL.getNamedTypeLoc(),
|
||||
T->getKeyword() != ElaboratedTypeKeyword::None ||
|
||||
T->getQualifier());
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL, bool TraverseQualifier) {
|
||||
return TraverseTypeLoc(TL.getUnqualifiedLoc(), TraverseQualifier);
|
||||
}
|
||||
|
||||
bool VisitDeclRefExpr(DeclRefExpr *S) {
|
||||
|
@ -37,15 +37,13 @@ void UseTransparentFunctorsCheck::registerMatchers(MatchFinder *Finder) {
|
||||
|
||||
// Non-transparent functor mentioned as a template parameter. FIXIT.
|
||||
Finder->addMatcher(
|
||||
loc(qualType(
|
||||
unless(elaboratedType()),
|
||||
hasDeclaration(classTemplateSpecializationDecl(
|
||||
unless(hasAnyTemplateArgument(templateArgument(refersToType(
|
||||
qualType(pointsTo(qualType(isAnyCharacter()))))))),
|
||||
hasAnyTemplateArgument(
|
||||
templateArgument(refersToType(qualType(hasDeclaration(
|
||||
TransparentFunctors))))
|
||||
.bind("Functor"))))))
|
||||
loc(qualType(hasDeclaration(classTemplateSpecializationDecl(
|
||||
unless(hasAnyTemplateArgument(templateArgument(refersToType(
|
||||
qualType(pointsTo(qualType(isAnyCharacter()))))))),
|
||||
hasAnyTemplateArgument(
|
||||
templateArgument(refersToType(qualType(
|
||||
hasDeclaration(TransparentFunctors))))
|
||||
.bind("Functor"))))))
|
||||
.bind("FunctorParentLoc"),
|
||||
this);
|
||||
|
||||
|
@ -42,11 +42,11 @@ void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// A matcher for a `DstT::DstT(const Src&)` where DstT also has a
|
||||
// `DstT::DstT(Src&&)`.
|
||||
const auto LValueRefCtor = cxxConstructorDecl(
|
||||
hasParameter(0,
|
||||
hasType(lValueReferenceType(pointee(type().bind("SrcT"))))),
|
||||
hasParameter(0, hasType(hasCanonicalType(
|
||||
lValueReferenceType(pointee(type().bind("SrcT")))))),
|
||||
ofClass(cxxRecordDecl(hasMethod(cxxConstructorDecl(
|
||||
hasParameter(0, hasType(rValueReferenceType(
|
||||
pointee(type(equalsBoundNode("SrcT")))))))))));
|
||||
hasParameter(0, hasType(hasCanonicalType(rValueReferenceType(
|
||||
pointee(type(equalsBoundNode("SrcT"))))))))))));
|
||||
|
||||
// A matcher for `DstT::DstT(const Src&&)`, which typically comes from an
|
||||
// instantiation of `template <typename U> DstT::DstT(U&&)`.
|
||||
|
@ -15,10 +15,11 @@ namespace clang::tidy::portability {
|
||||
|
||||
void StdAllocatorConstCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// Match std::allocator<const T>.
|
||||
auto AllocatorConst =
|
||||
auto AllocatorConst = qualType(hasCanonicalType(
|
||||
recordType(hasDeclaration(classTemplateSpecializationDecl(
|
||||
hasName("::std::allocator"),
|
||||
hasTemplateArgument(0, refersToType(qualType(isConstQualified()))))));
|
||||
hasTemplateArgument(0,
|
||||
refersToType(qualType(isConstQualified()))))))));
|
||||
|
||||
auto HasContainerName =
|
||||
hasAnyName("::std::vector", "::std::deque", "::std::list",
|
||||
@ -31,8 +32,10 @@ void StdAllocatorConstCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// aren't caught.
|
||||
Finder->addMatcher(
|
||||
typeLoc(
|
||||
templateSpecializationTypeLoc(),
|
||||
loc(hasUnqualifiedDesugaredType(anyOf(
|
||||
anyOf(templateSpecializationTypeLoc(),
|
||||
qualifiedTypeLoc(
|
||||
hasUnqualifiedLoc(templateSpecializationTypeLoc()))),
|
||||
loc(qualType(anyOf(
|
||||
recordType(hasDeclaration(classTemplateSpecializationDecl(
|
||||
HasContainerName,
|
||||
anyOf(
|
||||
|
@ -19,19 +19,25 @@ namespace {
|
||||
AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); }
|
||||
} // namespace
|
||||
|
||||
static unsigned getNameSpecifierNestingLevel(const QualType &QType) {
|
||||
if (const auto *ElType = QType->getAs<ElaboratedType>()) {
|
||||
if (const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier()) {
|
||||
unsigned NameSpecifierNestingLevel = 1;
|
||||
do {
|
||||
NameSpecifierNestingLevel++;
|
||||
NestedSpecifiers = NestedSpecifiers->getPrefix();
|
||||
} while (NestedSpecifiers);
|
||||
|
||||
static unsigned getNameSpecifierNestingLevel(QualType QType) {
|
||||
unsigned NameSpecifierNestingLevel = 1;
|
||||
for (NestedNameSpecifier Qualifier = QType->getPrefix(); /**/;
|
||||
++NameSpecifierNestingLevel) {
|
||||
switch (Qualifier.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
return NameSpecifierNestingLevel;
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
return NameSpecifierNestingLevel + 1;
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix;
|
||||
continue;
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
Qualifier = Qualifier.getAsType()->getPrefix();
|
||||
continue;
|
||||
}
|
||||
llvm_unreachable("unhandled nested name specifier kind");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StaticAccessedThroughInstanceCheck::storeOptions(
|
||||
|
@ -414,9 +414,9 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
|
||||
// Arithmetic types are interconvertible, except scoped enums.
|
||||
if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) {
|
||||
if ((ParamType->isEnumeralType() &&
|
||||
ParamType->castAs<EnumType>()->getDecl()->isScoped()) ||
|
||||
ParamType->castAs<EnumType>()->getOriginalDecl()->isScoped()) ||
|
||||
(ArgType->isEnumeralType() &&
|
||||
ArgType->castAs<EnumType>()->getDecl()->isScoped()))
|
||||
ArgType->castAs<EnumType>()->getOriginalDecl()->isScoped()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -67,11 +67,7 @@ static QualType getNonTemplateAlias(QualType QT) {
|
||||
if (!TT->getDecl()->getDescribedTemplate() &&
|
||||
!TT->getDecl()->getDeclContext()->isDependentContext())
|
||||
return QT;
|
||||
QT = TT->getDecl()->getUnderlyingType();
|
||||
}
|
||||
// cast to elaborated type
|
||||
else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(QT)) {
|
||||
QT = ET->getNamedType();
|
||||
QT = TT->desugar();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -66,7 +66,8 @@ ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base,
|
||||
if (!RecType)
|
||||
return State::Unknown;
|
||||
|
||||
const auto *BaseClass = cast<CXXRecordDecl>(RecType->getDecl());
|
||||
const auto *BaseClass =
|
||||
cast<CXXRecordDecl>(RecType->getOriginalDecl())->getDefinitionOrSelf();
|
||||
|
||||
return analyzeRecord(BaseClass, Kind);
|
||||
}
|
||||
|
@ -461,8 +461,9 @@ bool FormatStringConverter::emitIntegerArgument(
|
||||
// the signedness based on the format string, so we need to do the
|
||||
// same.
|
||||
if (const auto *ET = ArgType->getAs<EnumType>()) {
|
||||
if (const std::optional<std::string> MaybeCastType =
|
||||
castTypeForArgument(ArgKind, ET->getDecl()->getIntegerType()))
|
||||
if (const std::optional<std::string> MaybeCastType = castTypeForArgument(
|
||||
ArgKind,
|
||||
ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType()))
|
||||
ArgFixes.emplace_back(
|
||||
ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str());
|
||||
else
|
||||
|
@ -34,7 +34,7 @@ bool MatchesAnyListedTypeNameMatcher::matches(
|
||||
PrintingPolicy PrintingPolicyWithSuppressedTag(
|
||||
Finder->getASTContext().getLangOpts());
|
||||
PrintingPolicyWithSuppressedTag.PrintAsCanonical = CanonicalTypes;
|
||||
PrintingPolicyWithSuppressedTag.SuppressElaboration = true;
|
||||
PrintingPolicyWithSuppressedTag.FullyQualifiedName = true;
|
||||
PrintingPolicyWithSuppressedTag.SuppressScope = false;
|
||||
PrintingPolicyWithSuppressedTag.SuppressTagKeyword = true;
|
||||
PrintingPolicyWithSuppressedTag.SuppressUnwrittenScope = true;
|
||||
|
@ -281,9 +281,10 @@ public:
|
||||
}
|
||||
|
||||
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) {
|
||||
if (const NestedNameSpecifier *Spec = Loc.getNestedNameSpecifier()) {
|
||||
if (NestedNameSpecifier Spec = Loc.getNestedNameSpecifier();
|
||||
Spec.getKind() == NestedNameSpecifier::Kind::Namespace) {
|
||||
if (const auto *Decl =
|
||||
dyn_cast_if_present<NamespaceDecl>(Spec->getAsNamespace()))
|
||||
dyn_cast<NamespaceDecl>(Spec.getAsNamespaceAndPrefix().Namespace))
|
||||
Check->addUsage(Decl, Loc.getLocalSourceRange(), SM);
|
||||
}
|
||||
|
||||
@ -323,48 +324,34 @@ public:
|
||||
}
|
||||
|
||||
bool VisitTypedefTypeLoc(const TypedefTypeLoc &Loc) {
|
||||
Check->addUsage(Loc.getTypedefNameDecl(), Loc.getSourceRange(), SM);
|
||||
Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTagTypeLoc(const TagTypeLoc &Loc) {
|
||||
Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitInjectedClassNameTypeLoc(const InjectedClassNameTypeLoc &Loc) {
|
||||
Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
|
||||
Check->addUsage(Loc.getOriginalDecl(), Loc.getNameLoc(), SM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitUnresolvedUsingTypeLoc(const UnresolvedUsingTypeLoc &Loc) {
|
||||
Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
|
||||
Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTemplateTypeParmTypeLoc(const TemplateTypeParmTypeLoc &Loc) {
|
||||
Check->addUsage(Loc.getDecl(), Loc.getSourceRange(), SM);
|
||||
Check->addUsage(Loc.getDecl(), Loc.getNameLoc(), SM);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VisitTemplateSpecializationTypeLoc(const TemplateSpecializationTypeLoc &Loc) {
|
||||
const TemplateDecl *Decl =
|
||||
Loc.getTypePtr()->getTemplateName().getAsTemplateDecl();
|
||||
Loc.getTypePtr()->getTemplateName().getAsTemplateDecl(
|
||||
/*IgnoreDeduced=*/true);
|
||||
|
||||
SourceRange Range(Loc.getTemplateNameLoc(), Loc.getTemplateNameLoc());
|
||||
if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
|
||||
if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl))
|
||||
if (const NamedDecl *TemplDecl = ClassDecl->getTemplatedDecl())
|
||||
Check->addUsage(TemplDecl, Range, SM);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitDependentTemplateSpecializationTypeLoc(
|
||||
const DependentTemplateSpecializationTypeLoc &Loc) {
|
||||
if (const TagDecl *Decl = Loc.getTypePtr()->getAsTagDecl())
|
||||
Check->addUsage(Decl, Loc.getSourceRange(), SM);
|
||||
Check->addUsage(TemplDecl, Loc.getTemplateNameLoc(), SM);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -124,7 +124,8 @@ bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
|
||||
return true;
|
||||
|
||||
if (const auto *RT = CanonicalType->getAs<RecordType>()) {
|
||||
return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context);
|
||||
return recordIsTriviallyDefaultConstructible(
|
||||
*RT->getOriginalDecl()->getDefinitionOrSelf(), Context);
|
||||
}
|
||||
|
||||
// No other types can match.
|
||||
|
@ -102,54 +102,78 @@ getUsingNamespaceDirectives(const DeclContext *DestContext,
|
||||
// ancestor is redundant, therefore we stop at lowest common ancestor.
|
||||
// In addition to that stops early whenever IsVisible returns true. This can be
|
||||
// used to implement support for "using namespace" decls.
|
||||
std::string
|
||||
getQualification(ASTContext &Context, const DeclContext *DestContext,
|
||||
const DeclContext *SourceContext,
|
||||
llvm::function_ref<bool(NestedNameSpecifier *)> IsVisible) {
|
||||
std::vector<const NestedNameSpecifier *> Parents;
|
||||
bool ReachedNS = false;
|
||||
std::string getQualification(ASTContext &Context,
|
||||
const DeclContext *DestContext,
|
||||
const DeclContext *SourceContext,
|
||||
llvm::function_ref<bool(const Decl *)> IsVisible) {
|
||||
std::vector<const Decl *> Parents;
|
||||
[[maybe_unused]] bool ReachedNS = false;
|
||||
for (const DeclContext *CurContext = SourceContext; CurContext;
|
||||
CurContext = CurContext->getLookupParent()) {
|
||||
// Stop once we reach a common ancestor.
|
||||
if (CurContext->Encloses(DestContext))
|
||||
break;
|
||||
|
||||
NestedNameSpecifier *NNS = nullptr;
|
||||
const Decl *CurD;
|
||||
if (auto *TD = llvm::dyn_cast<TagDecl>(CurContext)) {
|
||||
// There can't be any more tag parents after hitting a namespace.
|
||||
assert(!ReachedNS);
|
||||
(void)ReachedNS;
|
||||
NNS = NestedNameSpecifier::Create(Context, nullptr, TD->getTypeForDecl());
|
||||
CurD = TD;
|
||||
} else if (auto *NSD = llvm::dyn_cast<NamespaceDecl>(CurContext)) {
|
||||
ReachedNS = true;
|
||||
NNS = NestedNameSpecifier::Create(Context, nullptr, NSD);
|
||||
// Anonymous and inline namespace names are not spelled while qualifying
|
||||
// a name, so skip those.
|
||||
if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace())
|
||||
continue;
|
||||
CurD = NSD;
|
||||
} else {
|
||||
// Other types of contexts cannot be spelled in code, just skip over
|
||||
// them.
|
||||
continue;
|
||||
}
|
||||
// Stop if this namespace is already visible at DestContext.
|
||||
if (IsVisible(NNS))
|
||||
if (IsVisible(CurD))
|
||||
break;
|
||||
|
||||
Parents.push_back(NNS);
|
||||
Parents.push_back(CurD);
|
||||
}
|
||||
|
||||
// Go over name-specifiers in reverse order to create necessary qualification,
|
||||
// since we stored inner-most parent first.
|
||||
// Go over the declarations in reverse order, since we stored inner-most
|
||||
// parent first.
|
||||
NestedNameSpecifier Qualifier = std::nullopt;
|
||||
bool IsFirst = true;
|
||||
for (const auto *CurD : llvm::reverse(Parents)) {
|
||||
if (auto *TD = llvm::dyn_cast<TagDecl>(CurD)) {
|
||||
QualType T;
|
||||
if (const auto *RD = dyn_cast<CXXRecordDecl>(TD);
|
||||
ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) {
|
||||
ArrayRef<TemplateArgument> Args;
|
||||
if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
|
||||
Args = SD->getTemplateArgs().asArray();
|
||||
else
|
||||
Args = CTD->getTemplateParameters()->getInjectedTemplateArgs(Context);
|
||||
T = Context.getTemplateSpecializationType(
|
||||
ElaboratedTypeKeyword::None,
|
||||
Context.getQualifiedTemplateName(
|
||||
Qualifier, /*TemplateKeyword=*/!IsFirst, TemplateName(CTD)),
|
||||
Args, /*CanonicalArgs=*/{}, Context.getCanonicalTagType(RD));
|
||||
} else {
|
||||
T = Context.getTagType(ElaboratedTypeKeyword::None, Qualifier, TD,
|
||||
/*OwnsTag=*/false);
|
||||
}
|
||||
Qualifier = NestedNameSpecifier(T.getTypePtr());
|
||||
} else {
|
||||
Qualifier =
|
||||
NestedNameSpecifier(Context, cast<NamespaceDecl>(CurD), Qualifier);
|
||||
}
|
||||
IsFirst = false;
|
||||
}
|
||||
if (!Qualifier)
|
||||
return "";
|
||||
|
||||
std::string Result;
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
for (const auto *Parent : llvm::reverse(Parents)) {
|
||||
if (Parent != *Parents.rbegin() && Parent->isDependent() &&
|
||||
Parent->getAsRecordDecl() &&
|
||||
Parent->getAsRecordDecl()->getDescribedClassTemplate())
|
||||
OS << "template ";
|
||||
Parent->print(OS, Context.getPrintingPolicy());
|
||||
}
|
||||
Qualifier.print(OS, Context.getPrintingPolicy());
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
@ -187,6 +211,7 @@ std::string printQualifiedName(const NamedDecl &ND) {
|
||||
// include them, but at query time it's hard to find all the inline
|
||||
// namespaces to query: the preamble doesn't have a dedicated list.
|
||||
Policy.SuppressUnwrittenScope = true;
|
||||
Policy.SuppressScope = true;
|
||||
// (unnamed struct), not (unnamed struct at /path/to/foo.cc:42:1).
|
||||
// In clangd, context is usually available and paths are mostly noise.
|
||||
Policy.AnonymousTagLocations = false;
|
||||
@ -213,8 +238,7 @@ std::string printUsingNamespaceName(const ASTContext &Ctx,
|
||||
std::string Name;
|
||||
llvm::raw_string_ostream Out(Name);
|
||||
|
||||
if (auto *Qual = D.getQualifier())
|
||||
Qual->print(Out, PP);
|
||||
D.getQualifier().print(Out, PP);
|
||||
D.getNominatedNamespaceAsWritten()->printName(Out);
|
||||
return Out.str();
|
||||
}
|
||||
@ -229,8 +253,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
|
||||
// Handle 'using namespace'. They all have the same name - <using-directive>.
|
||||
if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
|
||||
Out << "using namespace ";
|
||||
if (auto *Qual = UD->getQualifier())
|
||||
Qual->print(Out, PP);
|
||||
UD->getQualifier().print(Out, PP);
|
||||
UD->getNominatedNamespaceAsWritten()->printName(Out);
|
||||
return Out.str();
|
||||
}
|
||||
@ -250,8 +273,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
|
||||
}
|
||||
|
||||
// Print nested name qualifier if it was written in the source code.
|
||||
if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier())
|
||||
Qualifier->print(Out, PP);
|
||||
getQualifierLoc(ND).getNestedNameSpecifier().print(Out, PP);
|
||||
// Print the name itself.
|
||||
ND.getDeclName().print(Out, PP);
|
||||
// Print template arguments.
|
||||
@ -391,12 +413,13 @@ preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts,
|
||||
}
|
||||
|
||||
std::string printType(const QualType QT, const DeclContext &CurContext,
|
||||
const llvm::StringRef Placeholder) {
|
||||
const llvm::StringRef Placeholder, bool FullyQualify) {
|
||||
std::string Result;
|
||||
llvm::raw_string_ostream OS(Result);
|
||||
PrintingPolicy PP(CurContext.getParentASTContext().getPrintingPolicy());
|
||||
PP.SuppressTagKeyword = true;
|
||||
PP.SuppressUnwrittenScope = true;
|
||||
PP.FullyQualifiedName = FullyQualify;
|
||||
|
||||
class PrintCB : public PrintingCallbacks {
|
||||
public:
|
||||
@ -439,6 +462,7 @@ QualType declaredType(const TypeDecl *D) {
|
||||
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
|
||||
if (const auto *Args = CTSD->getTemplateArgsAsWritten())
|
||||
return Context.getTemplateSpecializationType(
|
||||
ElaboratedTypeKeyword::None,
|
||||
TemplateName(CTSD->getSpecializedTemplate()), Args->arguments(),
|
||||
/*CanonicalArgs=*/{});
|
||||
return Context.getTypeDeclType(D);
|
||||
@ -664,13 +688,10 @@ std::string getQualification(ASTContext &Context,
|
||||
auto VisibleNamespaceDecls =
|
||||
getUsingNamespaceDirectives(DestContext, InsertionPoint);
|
||||
return getQualification(
|
||||
Context, DestContext, ND->getDeclContext(),
|
||||
[&](NestedNameSpecifier *NNS) {
|
||||
const NamespaceDecl *NS =
|
||||
dyn_cast_if_present<NamespaceDecl>(NNS->getAsNamespace());
|
||||
if (!NS)
|
||||
Context, DestContext, ND->getDeclContext(), [&](const Decl *D) {
|
||||
if (D->getKind() != Decl::Namespace)
|
||||
return false;
|
||||
NS = NS->getCanonicalDecl();
|
||||
const auto *NS = cast<NamespaceDecl>(D)->getCanonicalDecl();
|
||||
return llvm::any_of(VisibleNamespaceDecls,
|
||||
[NS](const NamespaceDecl *NSD) {
|
||||
return NSD->getCanonicalDecl() == NS;
|
||||
@ -687,12 +708,11 @@ std::string getQualification(ASTContext &Context,
|
||||
(void)NS;
|
||||
}
|
||||
return getQualification(
|
||||
Context, DestContext, ND->getDeclContext(),
|
||||
[&](NestedNameSpecifier *NNS) {
|
||||
Context, DestContext, ND->getDeclContext(), [&](const Decl *D) {
|
||||
return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) {
|
||||
std::string NS;
|
||||
llvm::raw_string_ostream OS(NS);
|
||||
NNS->print(OS, Context.getPrintingPolicy());
|
||||
D->print(OS, Context.getPrintingPolicy());
|
||||
return OS.str() == Namespace;
|
||||
});
|
||||
});
|
||||
|
@ -135,7 +135,8 @@ preferredIncludeDirective(llvm::StringRef FileName, const LangOptions &LangOpts,
|
||||
/// Returns a QualType as string. The result doesn't contain unwritten scopes
|
||||
/// like anonymous/inline namespace.
|
||||
std::string printType(const QualType QT, const DeclContext &CurContext,
|
||||
llvm::StringRef Placeholder = "");
|
||||
llvm::StringRef Placeholder = "",
|
||||
bool FullyQualify = false);
|
||||
|
||||
/// Indicates if \p D is a template instantiation implicitly generated by the
|
||||
/// compiler, e.g.
|
||||
|
@ -1466,19 +1466,15 @@ bool allowIndex(CodeCompletionContext &CC) {
|
||||
auto Scope = CC.getCXXScopeSpecifier();
|
||||
if (!Scope)
|
||||
return true;
|
||||
NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
|
||||
if (!NameSpec)
|
||||
return true;
|
||||
// We only query the index when qualifier is a namespace.
|
||||
// If it's a class, we rely solely on sema completions.
|
||||
switch (NameSpec->getKind()) {
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Namespace:
|
||||
switch ((*Scope)->getScopeRep().getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
return true;
|
||||
case NestedNameSpecifier::Super:
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
// Unresolved inside a template.
|
||||
case NestedNameSpecifier::Identifier:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("invalid NestedNameSpecifier kind");
|
||||
|
@ -147,17 +147,17 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
|
||||
}
|
||||
llvm_unreachable("Unhandled ArgKind enum");
|
||||
}
|
||||
std::string getKind(const NestedNameSpecifierLoc &NNSL) {
|
||||
assert(NNSL.getNestedNameSpecifier());
|
||||
switch (NNSL.getNestedNameSpecifier()->getKind()) {
|
||||
std::string getKind(NestedNameSpecifierLoc NNSL) {
|
||||
switch (NNSL.getNestedNameSpecifier().getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
llvm_unreachable("unexpected null nested name specifier");
|
||||
#define NNS_KIND(X) \
|
||||
case NestedNameSpecifier::X: \
|
||||
case NestedNameSpecifier::Kind::X: \
|
||||
return #X
|
||||
NNS_KIND(Identifier);
|
||||
NNS_KIND(Namespace);
|
||||
NNS_KIND(TypeSpec);
|
||||
NNS_KIND(Type);
|
||||
NNS_KIND(Global);
|
||||
NNS_KIND(Super);
|
||||
NNS_KIND(MicrosoftSuper);
|
||||
#undef NNS_KIND
|
||||
}
|
||||
llvm_unreachable("Unhandled SpecifierKind enum");
|
||||
@ -261,7 +261,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
|
||||
return TL.getType().getLocalQualifiers().getAsString(
|
||||
Ctx.getPrintingPolicy());
|
||||
if (const auto *TT = dyn_cast<TagType>(TL.getTypePtr()))
|
||||
return getDetail(TT->getDecl());
|
||||
return getDetail(TT->getOriginalDecl());
|
||||
if (const auto *DT = dyn_cast<DeducedType>(TL.getTypePtr()))
|
||||
if (DT->isDeduced())
|
||||
return DT->getDeducedType().getAsString(Ctx.getPrintingPolicy());
|
||||
@ -273,16 +273,11 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
|
||||
return getDetail(TT->getDecl());
|
||||
return "";
|
||||
}
|
||||
std::string getDetail(const NestedNameSpecifierLoc &NNSL) {
|
||||
const auto &NNS = *NNSL.getNestedNameSpecifier();
|
||||
switch (NNS.getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
return NNS.getAsIdentifier()->getName().str() + "::";
|
||||
case NestedNameSpecifier::Namespace:
|
||||
return NNS.getAsNamespace()->getNameAsString() + "::";
|
||||
default:
|
||||
std::string getDetail(NestedNameSpecifierLoc NNSL) {
|
||||
NestedNameSpecifier NNS = NNSL.getNestedNameSpecifier();
|
||||
if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace)
|
||||
return "";
|
||||
}
|
||||
return NNS.getAsNamespaceAndPrefix().Namespace->getNameAsString() + "::";
|
||||
}
|
||||
std::string getDetail(const CXXCtorInitializer *CCI) {
|
||||
if (FieldDecl *FD = CCI->getAnyMember())
|
||||
@ -346,8 +341,10 @@ public:
|
||||
return !D || isInjectedClassName(D) ||
|
||||
traverseNode("declaration", D, [&] { Base::TraverseDecl(D); });
|
||||
}
|
||||
bool TraverseTypeLoc(TypeLoc TL) {
|
||||
return !TL || traverseNode("type", TL, [&] { Base::TraverseTypeLoc(TL); });
|
||||
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
|
||||
return !TL || traverseNode("type", TL, [&] {
|
||||
Base::TraverseTypeLoc(TL, TraverseQualifier);
|
||||
});
|
||||
}
|
||||
bool TraverseTemplateName(const TemplateName &TN) {
|
||||
return traverseNode("template name", TN,
|
||||
@ -389,11 +386,11 @@ public:
|
||||
// This means we'd never see 'int' in 'const int'! Work around that here.
|
||||
// (The reason for the behavior is to avoid traversing the nested Type twice,
|
||||
// but we ignore TraverseType anyway).
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL) {
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL, bool TraverseQualifier) {
|
||||
return TraverseTypeLoc(QTL.getUnqualifiedLoc());
|
||||
}
|
||||
// Uninteresting parts of the AST that don't have locations within them.
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; }
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; }
|
||||
bool TraverseType(QualType) { return true; }
|
||||
|
||||
// OpaqueValueExpr blocks traversal, we must explicitly traverse it.
|
||||
@ -420,7 +417,7 @@ ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens,
|
||||
V.TraverseNestedNameSpecifierLoc(
|
||||
*const_cast<NestedNameSpecifierLoc *>(NNSL));
|
||||
else if (const auto *NNS = N.get<NestedNameSpecifier>())
|
||||
V.TraverseNestedNameSpecifier(const_cast<NestedNameSpecifier *>(NNS));
|
||||
V.TraverseNestedNameSpecifier(*NNS);
|
||||
else if (const auto *TL = N.get<TypeLoc>())
|
||||
V.TraverseTypeLoc(*const_cast<TypeLoc *>(TL));
|
||||
else if (const auto *QT = N.get<QualType>())
|
||||
|
@ -366,19 +366,11 @@ public:
|
||||
Visitor(TargetFinder &Outer, RelSet Flags) : Outer(Outer), Flags(Flags) {}
|
||||
|
||||
void VisitTagType(const TagType *TT) {
|
||||
Outer.add(TT->getAsTagDecl(), Flags);
|
||||
}
|
||||
|
||||
void VisitElaboratedType(const ElaboratedType *ET) {
|
||||
Outer.add(ET->desugar(), Flags);
|
||||
Outer.add(cast<TagType>(TT)->getOriginalDecl(), Flags);
|
||||
}
|
||||
|
||||
void VisitUsingType(const UsingType *ET) {
|
||||
Outer.add(ET->getFoundDecl(), Flags);
|
||||
}
|
||||
|
||||
void VisitInjectedClassNameType(const InjectedClassNameType *ICNT) {
|
||||
Outer.add(ICNT->getDecl(), Flags);
|
||||
Outer.add(ET->getDecl(), Flags);
|
||||
}
|
||||
|
||||
void VisitDecltypeType(const DecltypeType *DTT) {
|
||||
@ -483,30 +475,27 @@ public:
|
||||
Visitor(*this, Flags).Visit(T.getTypePtr());
|
||||
}
|
||||
|
||||
void add(const NestedNameSpecifier *NNS, RelSet Flags) {
|
||||
void add(NestedNameSpecifier NNS, RelSet Flags) {
|
||||
if (!NNS)
|
||||
return;
|
||||
debug(*NNS, Flags);
|
||||
switch (NNS->getKind()) {
|
||||
case NestedNameSpecifier::Namespace:
|
||||
add(NNS->getAsNamespace(), Flags);
|
||||
debug(NNS, Flags);
|
||||
switch (NNS.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
add(NNS.getAsNamespaceAndPrefix().Namespace, Flags);
|
||||
return;
|
||||
case NestedNameSpecifier::Identifier:
|
||||
if (Resolver) {
|
||||
add(Resolver->resolveNestedNameSpecifierToType(NNS), Flags);
|
||||
}
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
add(QualType(NNS.getAsType(), 0), Flags);
|
||||
return;
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
add(QualType(NNS->getAsType(), 0), Flags);
|
||||
return;
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
// This should be TUDecl, but we can't get a pointer to it!
|
||||
return;
|
||||
case NestedNameSpecifier::Super:
|
||||
add(NNS->getAsRecordDecl(), Flags);
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
add(NNS.getAsMicrosoftSuper(), Flags);
|
||||
return;
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
llvm_unreachable("unexpected null nested name specifier");
|
||||
}
|
||||
llvm_unreachable("unhandled NestedNameSpecifier::SpecifierKind");
|
||||
llvm_unreachable("unhandled NestedNameSpecifier::Kind");
|
||||
}
|
||||
|
||||
void add(const CXXCtorInitializer *CCI, RelSet Flags) {
|
||||
@ -555,7 +544,7 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) {
|
||||
else if (const NestedNameSpecifierLoc *NNSL = N.get<NestedNameSpecifierLoc>())
|
||||
Finder.add(NNSL->getNestedNameSpecifier(), Flags);
|
||||
else if (const NestedNameSpecifier *NNS = N.get<NestedNameSpecifier>())
|
||||
Finder.add(NNS, Flags);
|
||||
Finder.add(*NNS, Flags);
|
||||
else if (const TypeLoc *TL = N.get<TypeLoc>())
|
||||
Finder.add(TL->getType(), Flags);
|
||||
else if (const QualType *QT = N.get<QualType>())
|
||||
@ -861,32 +850,25 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
|
||||
const HeuristicResolver *Resolver;
|
||||
llvm::SmallVector<ReferenceLoc> Refs;
|
||||
|
||||
void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) {
|
||||
// We only know about qualifier, rest if filled by inner locations.
|
||||
size_t InitialSize = Refs.size();
|
||||
Visit(L.getNamedTypeLoc().getUnqualifiedLoc());
|
||||
size_t NewSize = Refs.size();
|
||||
// Add qualifier for the newly-added refs.
|
||||
for (unsigned I = InitialSize; I < NewSize; ++I) {
|
||||
ReferenceLoc *Ref = &Refs[I];
|
||||
// Fill in the qualifier.
|
||||
assert(!Ref->Qualifier.hasQualifier() && "qualifier already set");
|
||||
Ref->Qualifier = L.getQualifierLoc();
|
||||
}
|
||||
void VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc L) {
|
||||
Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
|
||||
L.getLocalSourceRange().getBegin(),
|
||||
/*IsDecl=*/false,
|
||||
{L.getDecl()}});
|
||||
}
|
||||
|
||||
void VisitUsingTypeLoc(UsingTypeLoc L) {
|
||||
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||
Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
|
||||
L.getLocalSourceRange().getBegin(),
|
||||
/*IsDecl=*/false,
|
||||
{L.getFoundDecl()}});
|
||||
{L.getDecl()}});
|
||||
}
|
||||
|
||||
void VisitTagTypeLoc(TagTypeLoc L) {
|
||||
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||
Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
|
||||
L.getNameLoc(),
|
||||
/*IsDecl=*/false,
|
||||
{L.getDecl()}});
|
||||
{L.getOriginalDecl()}});
|
||||
}
|
||||
|
||||
void VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc L) {
|
||||
@ -906,25 +888,18 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
|
||||
// 2. 'vector<int>' with mask 'Underlying'.
|
||||
// we want to return only #1 in this case.
|
||||
Refs.push_back(ReferenceLoc{
|
||||
NestedNameSpecifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false,
|
||||
L.getQualifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false,
|
||||
explicitReferenceTargets(DynTypedNode::create(L.getType()),
|
||||
DeclRelation::Alias, Resolver)});
|
||||
}
|
||||
void VisitDeducedTemplateSpecializationTypeLoc(
|
||||
DeducedTemplateSpecializationTypeLoc L) {
|
||||
Refs.push_back(ReferenceLoc{
|
||||
NestedNameSpecifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
|
||||
L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false,
|
||||
explicitReferenceTargets(DynTypedNode::create(L.getType()),
|
||||
DeclRelation::Alias, Resolver)});
|
||||
}
|
||||
|
||||
void VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) {
|
||||
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||
TL.getNameLoc(),
|
||||
/*IsDecl=*/false,
|
||||
{TL.getDecl()}});
|
||||
}
|
||||
|
||||
void VisitDependentTemplateSpecializationTypeLoc(
|
||||
DependentTemplateSpecializationTypeLoc L) {
|
||||
Refs.push_back(
|
||||
@ -943,12 +918,12 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) {
|
||||
}
|
||||
|
||||
void VisitTypedefTypeLoc(TypedefTypeLoc L) {
|
||||
if (shouldSkipTypedef(L.getTypedefNameDecl()))
|
||||
if (shouldSkipTypedef(L.getDecl()))
|
||||
return;
|
||||
Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(),
|
||||
Refs.push_back(ReferenceLoc{L.getQualifierLoc(),
|
||||
L.getNameLoc(),
|
||||
/*IsDecl=*/false,
|
||||
{L.getTypedefNameDecl()}});
|
||||
{L.getDecl()}});
|
||||
}
|
||||
|
||||
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc L) {
|
||||
@ -980,17 +955,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc L) {
|
||||
// ElaboratedTypeLoc will reports information for its inner type loc.
|
||||
// Otherwise we loose information about inner types loc's qualifier.
|
||||
TypeLoc Inner = L.getNamedTypeLoc().getUnqualifiedLoc();
|
||||
if (L.getBeginLoc() == Inner.getBeginLoc())
|
||||
return RecursiveASTVisitor::TraverseTypeLoc(Inner);
|
||||
else
|
||||
TypeLocsToSkip.insert(Inner.getBeginLoc());
|
||||
return RecursiveASTVisitor::TraverseElaboratedTypeLoc(L);
|
||||
}
|
||||
|
||||
bool VisitStmt(Stmt *S) {
|
||||
visitNode(DynTypedNode::create(*S));
|
||||
return true;
|
||||
@ -1051,7 +1015,7 @@ public:
|
||||
return true;
|
||||
visitNode(DynTypedNode::create(L));
|
||||
// Inner type is missing information about its qualifier, skip it.
|
||||
if (auto TL = L.getTypeLoc())
|
||||
if (auto TL = L.getAsTypeLoc())
|
||||
TypeLocsToSkip.insert(TL.getBeginLoc());
|
||||
return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(L);
|
||||
}
|
||||
@ -1092,12 +1056,21 @@ private:
|
||||
if (auto *S = N.get<Stmt>())
|
||||
return refInStmt(S, Resolver);
|
||||
if (auto *NNSL = N.get<NestedNameSpecifierLoc>()) {
|
||||
// (!) 'DeclRelation::Alias' ensures we do not loose namespace aliases.
|
||||
return {ReferenceLoc{
|
||||
NNSL->getPrefix(), NNSL->getLocalBeginLoc(), false,
|
||||
explicitReferenceTargets(
|
||||
DynTypedNode::create(*NNSL->getNestedNameSpecifier()),
|
||||
DeclRelation::Alias, Resolver)}};
|
||||
// (!) 'DeclRelation::Alias' ensures we do not lose namespace aliases.
|
||||
NestedNameSpecifierLoc Qualifier;
|
||||
SourceLocation NameLoc;
|
||||
if (auto TL = NNSL->getAsTypeLoc()) {
|
||||
Qualifier = TL.getPrefix();
|
||||
NameLoc = TL.getNonPrefixBeginLoc();
|
||||
} else {
|
||||
Qualifier = NNSL->getAsNamespaceAndPrefix().Prefix;
|
||||
NameLoc = NNSL->getLocalBeginLoc();
|
||||
}
|
||||
return {
|
||||
ReferenceLoc{Qualifier, NameLoc, false,
|
||||
explicitReferenceTargets(
|
||||
DynTypedNode::create(NNSL->getNestedNameSpecifier()),
|
||||
DeclRelation::Alias, Resolver)}};
|
||||
}
|
||||
if (const TypeLoc *TL = N.get<TypeLoc>())
|
||||
return refInTypeLoc(*TL, Resolver);
|
||||
@ -1210,8 +1183,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R) {
|
||||
OS << "}";
|
||||
if (R.Qualifier) {
|
||||
OS << ", qualifier = '";
|
||||
R.Qualifier.getNestedNameSpecifier()->print(OS,
|
||||
PrintingPolicy(LangOptions()));
|
||||
R.Qualifier.getNestedNameSpecifier().print(OS,
|
||||
PrintingPolicy(LangOptions()));
|
||||
OS << "'";
|
||||
}
|
||||
if (R.IsDecl)
|
||||
|
@ -172,13 +172,14 @@ HoverInfo::PrintedType printType(QualType QT, ASTContext &ASTCtx,
|
||||
QT = QT->castAs<DecltypeType>()->getUnderlyingType();
|
||||
HoverInfo::PrintedType Result;
|
||||
llvm::raw_string_ostream OS(Result.Type);
|
||||
// Special case: if the outer type is a tag type without qualifiers, then
|
||||
// include the tag for extra clarity.
|
||||
// This isn't very idiomatic, so don't attempt it for complex cases, including
|
||||
// pointers/references, template specializations, etc.
|
||||
// Special case: if the outer type is a canonical tag type, then include the
|
||||
// tag for extra clarity. This isn't very idiomatic, so don't attempt it for
|
||||
// complex cases, including pointers/references, template specializations,
|
||||
// etc.
|
||||
if (!QT.isNull() && !QT.hasQualifiers() && PP.SuppressTagKeyword) {
|
||||
if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr()))
|
||||
OS << TT->getDecl()->getKindName() << " ";
|
||||
if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr());
|
||||
TT && TT->isCanonicalUnqualified())
|
||||
OS << TT->getOriginalDecl()->getKindName() << " ";
|
||||
}
|
||||
QT.print(OS, PP);
|
||||
|
||||
@ -454,7 +455,7 @@ std::optional<std::string> printExprValue(const Expr *E,
|
||||
// Compare to int64_t to avoid bit-width match requirements.
|
||||
int64_t Val = Constant.Val.getInt().getExtValue();
|
||||
for (const EnumConstantDecl *ECD :
|
||||
T->castAs<EnumType>()->getDecl()->enumerators())
|
||||
T->castAs<EnumType>()->getOriginalDecl()->enumerators())
|
||||
if (ECD->getInitVal() == Val)
|
||||
return llvm::formatv("{0} ({1})", ECD->getNameAsString(),
|
||||
printHex(Constant.Val.getInt()))
|
||||
@ -972,10 +973,11 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
|
||||
|
||||
const auto &Ctx = ND.getASTContext();
|
||||
if (auto *RD = llvm::dyn_cast<RecordDecl>(&ND)) {
|
||||
if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RD->getTypeForDecl()))
|
||||
CanQualType RT = Ctx.getCanonicalTagType(RD);
|
||||
if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RT))
|
||||
HI.Size = Size->getQuantity() * 8;
|
||||
if (!RD->isDependentType() && RD->isCompleteDefinition())
|
||||
HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl());
|
||||
HI.Align = Ctx.getTypeAlign(RT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,7 @@ std::vector<Fix> IncludeFixer::fix(DiagnosticsEngine::Level DiagLevel,
|
||||
// `enum x : int;' is not formally an incomplete type.
|
||||
// We may need a full definition anyway.
|
||||
if (auto * ET = llvm::dyn_cast<EnumType>(T))
|
||||
if (!ET->getDecl()->getDefinition())
|
||||
if (!ET->getOriginalDecl()->getDefinition())
|
||||
return fixIncompleteType(*T);
|
||||
}
|
||||
}
|
||||
@ -400,35 +400,35 @@ std::optional<CheapUnresolvedName> extractUnresolvedNameCheaply(
|
||||
CheapUnresolvedName Result;
|
||||
Result.Name = Unresolved.getAsString();
|
||||
if (SS && SS->isNotEmpty()) { // "::" or "ns::"
|
||||
if (auto *Nested = SS->getScopeRep()) {
|
||||
if (Nested->getKind() == NestedNameSpecifier::Global) {
|
||||
Result.ResolvedScope = "";
|
||||
} else if (const NamespaceBaseDecl *NSB = Nested->getAsNamespace()) {
|
||||
if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) {
|
||||
std::string SpecifiedNS = printNamespaceScope(*NS);
|
||||
std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM);
|
||||
NestedNameSpecifier Nested = SS->getScopeRep();
|
||||
if (Nested.getKind() == NestedNameSpecifier::Kind::Global) {
|
||||
Result.ResolvedScope = "";
|
||||
} else if (Nested.getKind() == NestedNameSpecifier::Kind::Namespace) {
|
||||
const NamespaceBaseDecl *NSB = Nested.getAsNamespaceAndPrefix().Namespace;
|
||||
if (const auto *NS = dyn_cast<NamespaceDecl>(NSB)) {
|
||||
std::string SpecifiedNS = printNamespaceScope(*NS);
|
||||
std::optional<std::string> Spelling = getSpelledSpecifier(*SS, SM);
|
||||
|
||||
// Check the specifier spelled in the source.
|
||||
// If the resolved scope doesn't end with the spelled scope, the
|
||||
// resolved scope may come from a sema typo correction. For example,
|
||||
// sema assumes that "clangd::" is a typo of "clang::" and uses
|
||||
// "clang::" as the specified scope in:
|
||||
// namespace clang { clangd::X; }
|
||||
// In this case, we use the "typo" specifier as extra scope instead
|
||||
// of using the scope assumed by sema.
|
||||
if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) {
|
||||
Result.ResolvedScope = std::move(SpecifiedNS);
|
||||
} else {
|
||||
Result.UnresolvedScope = std::move(*Spelling);
|
||||
}
|
||||
// Check the specifier spelled in the source.
|
||||
// If the resolved scope doesn't end with the spelled scope, the
|
||||
// resolved scope may come from a sema typo correction. For example,
|
||||
// sema assumes that "clangd::" is a typo of "clang::" and uses
|
||||
// "clang::" as the specified scope in:
|
||||
// namespace clang { clangd::X; }
|
||||
// In this case, we use the "typo" specifier as extra scope instead
|
||||
// of using the scope assumed by sema.
|
||||
if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) {
|
||||
Result.ResolvedScope = std::move(SpecifiedNS);
|
||||
} else {
|
||||
Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace());
|
||||
Result.UnresolvedScope = std::move(*Spelling);
|
||||
}
|
||||
} else {
|
||||
// We don't fix symbols in scopes that are not top-level e.g. class
|
||||
// members, as we don't collect includes for them.
|
||||
return std::nullopt;
|
||||
Result.ResolvedScope = printNamespaceScope(*cast<NamespaceAliasDecl>(NSB)->getNamespace());
|
||||
}
|
||||
} else {
|
||||
// We don't fix symbols in scopes that are not top-level e.g. class
|
||||
// members, as we don't collect includes for them.
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,18 +55,24 @@ void stripLeadingUnderscores(StringRef &Name) { Name = Name.ltrim('_'); }
|
||||
|
||||
// getDeclForType() returns the decl responsible for Type's spelling.
|
||||
// This is the inverse of ASTContext::getTypeDeclType().
|
||||
template <typename Ty, typename = decltype(((Ty *)nullptr)->getDecl())>
|
||||
const NamedDecl *getDeclForTypeImpl(const Ty *T) {
|
||||
return T->getDecl();
|
||||
}
|
||||
const NamedDecl *getDeclForTypeImpl(const void *T) { return nullptr; }
|
||||
const NamedDecl *getDeclForType(const Type *T) {
|
||||
switch (T->getTypeClass()) {
|
||||
#define ABSTRACT_TYPE(TY, BASE)
|
||||
#define TYPE(TY, BASE) \
|
||||
case Type::TY: \
|
||||
return getDeclForTypeImpl(llvm::cast<TY##Type>(T));
|
||||
#include "clang/AST/TypeNodes.inc"
|
||||
case Type::Enum:
|
||||
case Type::Record:
|
||||
case Type::InjectedClassName:
|
||||
return cast<TagType>(T)->getOriginalDecl();
|
||||
case Type::TemplateSpecialization:
|
||||
return cast<TemplateSpecializationType>(T)
|
||||
->getTemplateName()
|
||||
.getAsTemplateDecl(/*IgnoreDeduced=*/true);
|
||||
case Type::Typedef:
|
||||
return cast<TypedefType>(T)->getDecl();
|
||||
case Type::UnresolvedUsing:
|
||||
return cast<UnresolvedUsingType>(T)->getDecl();
|
||||
case Type::Using:
|
||||
return cast<UsingType>(T)->getDecl();
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
llvm_unreachable("Unknown TypeClass enum");
|
||||
}
|
||||
@ -81,8 +87,6 @@ llvm::StringRef getSimpleName(const NamedDecl &D) {
|
||||
return getSimpleName(D.getDeclName());
|
||||
}
|
||||
llvm::StringRef getSimpleName(QualType T) {
|
||||
if (const auto *ET = llvm::dyn_cast<ElaboratedType>(T))
|
||||
return getSimpleName(ET->getNamedType());
|
||||
if (const auto *BT = llvm::dyn_cast<BuiltinType>(T)) {
|
||||
PrintingPolicy PP(LangOptions{});
|
||||
PP.adjustForCPlusPlus();
|
||||
|
@ -62,7 +62,8 @@ void recordMetrics(const SelectionTree &S, const LangOptions &Lang) {
|
||||
}
|
||||
|
||||
// Return the range covering a node and all its children.
|
||||
SourceRange getSourceRange(const DynTypedNode &N) {
|
||||
SourceRange getSourceRange(const DynTypedNode &N,
|
||||
bool IncludeQualifier = false) {
|
||||
// MemberExprs to implicitly access anonymous fields should not claim any
|
||||
// tokens for themselves. Given:
|
||||
// struct A { struct { int b; }; };
|
||||
@ -80,7 +81,7 @@ SourceRange getSourceRange(const DynTypedNode &N) {
|
||||
? getSourceRange(DynTypedNode::create(*ME->getBase()))
|
||||
: SourceRange();
|
||||
}
|
||||
return N.getSourceRange();
|
||||
return N.getSourceRange(IncludeQualifier);
|
||||
}
|
||||
|
||||
// An IntervalSet maintains a set of disjoint subranges of an array.
|
||||
@ -643,8 +644,9 @@ public:
|
||||
}
|
||||
return traverseNode(X, [&] { return Base::TraverseDecl(X); });
|
||||
}
|
||||
bool TraverseTypeLoc(TypeLoc X) {
|
||||
return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); });
|
||||
bool TraverseTypeLoc(TypeLoc X, bool TraverseQualifier = true) {
|
||||
return traverseNode(
|
||||
&X, [&] { return Base::TraverseTypeLoc(X, TraverseQualifier); });
|
||||
}
|
||||
bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &X) {
|
||||
return traverseNode(&X,
|
||||
@ -690,7 +692,8 @@ public:
|
||||
// This means we'd never see 'int' in 'const int'! Work around that here.
|
||||
// (The reason for the behavior is to avoid traversing the nested Type twice,
|
||||
// but we ignore TraverseType anyway).
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX) {
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QX,
|
||||
bool TraverseQualifier = true) {
|
||||
return traverseNode<TypeLoc>(
|
||||
&QX, [&] { return TraverseTypeLoc(QX.getUnqualifiedLoc()); });
|
||||
}
|
||||
@ -698,7 +701,7 @@ public:
|
||||
return traverseNode(&PL, [&] { return Base::TraverseObjCProtocolLoc(PL); });
|
||||
}
|
||||
// Uninteresting parts of the AST that don't have locations within them.
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; }
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; }
|
||||
bool TraverseType(QualType) { return true; }
|
||||
|
||||
// The DeclStmt for the loop variable claims to cover the whole range
|
||||
@ -798,7 +801,7 @@ private:
|
||||
// An optimization for a common case: nodes outside macro expansions that
|
||||
// don't intersect the selection may be recursively skipped.
|
||||
bool canSafelySkipNode(const DynTypedNode &N) {
|
||||
SourceRange S = getSourceRange(N);
|
||||
SourceRange S = getSourceRange(N, /*IncludeQualifier=*/true);
|
||||
if (auto *TL = N.get<TypeLoc>()) {
|
||||
// FIXME: TypeLoc::getBeginLoc()/getEndLoc() are pretty fragile
|
||||
// heuristics. We should consider only pruning critical TypeLoc nodes, to
|
||||
|
@ -1127,21 +1127,6 @@ public:
|
||||
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L);
|
||||
}
|
||||
|
||||
// findExplicitReferences will walk nested-name-specifiers and
|
||||
// find anything that can be resolved to a Decl. However, non-leaf
|
||||
// components of nested-name-specifiers which are dependent names
|
||||
// (kind "Identifier") cannot be resolved to a decl, so we visit
|
||||
// them here.
|
||||
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
|
||||
if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
|
||||
if (NNS->getKind() == NestedNameSpecifier::Identifier)
|
||||
H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type)
|
||||
.addModifier(HighlightingModifier::DependentName)
|
||||
.addModifier(HighlightingModifier::ClassScope);
|
||||
}
|
||||
return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
|
||||
}
|
||||
|
||||
private:
|
||||
HighlightingsBuilder &H;
|
||||
};
|
||||
|
@ -1965,7 +1965,8 @@ std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST,
|
||||
|
||||
// Return the type most associated with an AST node.
|
||||
// This isn't precisely defined: we want "go to type" to do something useful.
|
||||
static QualType typeForNode(const SelectionTree::Node *N) {
|
||||
static QualType typeForNode(const ASTContext &Ctx,
|
||||
const SelectionTree::Node *N) {
|
||||
// If we're looking at a namespace qualifier, walk up to what it's qualifying.
|
||||
// (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).
|
||||
while (N && N->ASTNode.get<NestedNameSpecifierLoc>())
|
||||
@ -1999,10 +2000,13 @@ static QualType typeForNode(const SelectionTree::Node *N) {
|
||||
|
||||
if (const Decl *D = N->ASTNode.get<Decl>()) {
|
||||
struct Visitor : ConstDeclVisitor<Visitor, QualType> {
|
||||
const ASTContext &Ctx;
|
||||
Visitor(const ASTContext &Ctx) : Ctx(Ctx) {}
|
||||
|
||||
QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }
|
||||
// Declaration of a type => that type.
|
||||
QualType VisitTypeDecl(const TypeDecl *D) {
|
||||
return QualType(D->getTypeForDecl(), 0);
|
||||
return Ctx.getTypeDeclType(D);
|
||||
}
|
||||
// Exception: alias declaration => the underlying type, not the alias.
|
||||
QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {
|
||||
@ -2012,7 +2016,7 @@ static QualType typeForNode(const SelectionTree::Node *N) {
|
||||
QualType VisitTemplateDecl(const TemplateDecl *D) {
|
||||
return Visit(D->getTemplatedDecl());
|
||||
}
|
||||
} V;
|
||||
} V(Ctx);
|
||||
return V.Visit(D);
|
||||
}
|
||||
|
||||
@ -2156,7 +2160,8 @@ std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos,
|
||||
// unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some
|
||||
// information about the type you may have not known before
|
||||
// (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).
|
||||
for (const QualType& Type : unwrapFindType(typeForNode(N), AST.getHeuristicResolver()))
|
||||
for (const QualType &Type : unwrapFindType(
|
||||
typeForNode(AST.getASTContext(), N), AST.getHeuristicResolver()))
|
||||
llvm::copy(locateSymbolForType(AST, Type, Index),
|
||||
std::back_inserter(LocatedSymbols));
|
||||
|
||||
|
@ -115,13 +115,6 @@ private:
|
||||
const SourceManager &SM;
|
||||
};
|
||||
|
||||
bool isFullyQualified(const NestedNameSpecifier *NNS) {
|
||||
if (!NNS)
|
||||
return false;
|
||||
return NNS->getKind() == NestedNameSpecifier::Global ||
|
||||
isFullyQualified(NNS->getPrefix());
|
||||
}
|
||||
|
||||
struct InsertionPointData {
|
||||
// Location to insert the "using" statement. If invalid then the statement
|
||||
// should not be inserted at all (it already exists).
|
||||
@ -167,18 +160,20 @@ findInsertionPoint(const Tweak::Selection &Inputs,
|
||||
for (auto &U : Usings) {
|
||||
// Only "upgrade" to fully qualified is all relevant using decls are fully
|
||||
// qualified. Otherwise trust what the user typed.
|
||||
if (!isFullyQualified(U->getQualifier()))
|
||||
if (!U->getQualifier().isFullyQualified())
|
||||
AlwaysFullyQualify = false;
|
||||
|
||||
if (SM.isBeforeInTranslationUnit(Inputs.Cursor, U->getUsingLoc()))
|
||||
// "Usings" is sorted, so we're done.
|
||||
break;
|
||||
if (const auto *Namespace = dyn_cast_if_present<NamespaceDecl>(
|
||||
U->getQualifier()->getAsNamespace())) {
|
||||
if (NestedNameSpecifier Qualifier = U->getQualifier();
|
||||
Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) {
|
||||
const auto *Namespace =
|
||||
U->getQualifier().getAsNamespaceAndPrefix().Namespace;
|
||||
if (Namespace->getCanonicalDecl() ==
|
||||
QualifierToRemove.getNestedNameSpecifier()
|
||||
->getAsNamespace()
|
||||
->getCanonicalDecl() &&
|
||||
.getAsNamespaceAndPrefix()
|
||||
.Namespace->getCanonicalDecl() &&
|
||||
U->getName() == Name) {
|
||||
return InsertionPointData();
|
||||
}
|
||||
@ -232,8 +227,9 @@ findInsertionPoint(const Tweak::Selection &Inputs,
|
||||
}
|
||||
|
||||
bool isNamespaceForbidden(const Tweak::Selection &Inputs,
|
||||
const NestedNameSpecifier &Namespace) {
|
||||
const auto *NS = dyn_cast<NamespaceDecl>(Namespace.getAsNamespace());
|
||||
NestedNameSpecifier Namespace) {
|
||||
const auto *NS =
|
||||
dyn_cast<NamespaceDecl>(Namespace.getAsNamespaceAndPrefix().Namespace);
|
||||
if (!NS)
|
||||
return true;
|
||||
std::string NamespaceStr = printNamespaceScope(*NS);
|
||||
@ -247,11 +243,11 @@ bool isNamespaceForbidden(const Tweak::Selection &Inputs,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getNNSLAsString(NestedNameSpecifierLoc &NNSL,
|
||||
std::string getNNSLAsString(NestedNameSpecifierLoc NNSL,
|
||||
const PrintingPolicy &Policy) {
|
||||
std::string Out;
|
||||
llvm::raw_string_ostream OutStream(Out);
|
||||
NNSL.getNestedNameSpecifier()->print(OutStream, Policy);
|
||||
NNSL.getNestedNameSpecifier().print(OutStream, Policy);
|
||||
return OutStream.str();
|
||||
}
|
||||
|
||||
@ -276,16 +272,15 @@ bool AddUsing::prepare(const Selection &Inputs) {
|
||||
continue;
|
||||
}
|
||||
if (auto *T = Node->ASTNode.get<TypeLoc>()) {
|
||||
if (T->getAs<ElaboratedTypeLoc>()) {
|
||||
break;
|
||||
}
|
||||
if (Node->Parent->ASTNode.get<TypeLoc>() ||
|
||||
Node->Parent->ASTNode.get<NestedNameSpecifierLoc>()) {
|
||||
// Node is TypeLoc, but it's parent is either TypeLoc or
|
||||
// NestedNameSpecifier. In both cases, we want to go up, to find
|
||||
// the outermost TypeLoc.
|
||||
// Find the outermost TypeLoc.
|
||||
if (Node->Parent->ASTNode.get<NestedNameSpecifierLoc>())
|
||||
continue;
|
||||
if (isa<TagType, TemplateSpecializationType, TypedefType, UsingType,
|
||||
UnresolvedUsingType>(T->getTypePtr()))
|
||||
break;
|
||||
// Find the outermost TypeLoc.
|
||||
if (Node->Parent->ASTNode.get<TypeLoc>())
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -307,32 +302,70 @@ bool AddUsing::prepare(const Selection &Inputs) {
|
||||
MustInsertAfterLoc = D->getDecl()->getBeginLoc();
|
||||
}
|
||||
} else if (auto *T = Node->ASTNode.get<TypeLoc>()) {
|
||||
if (auto E = T->getAs<ElaboratedTypeLoc>()) {
|
||||
QualifierToRemove = E.getQualifierLoc();
|
||||
|
||||
SpelledNameRange = E.getSourceRange();
|
||||
if (auto T = E.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>()) {
|
||||
// Remove the template arguments from the name.
|
||||
SpelledNameRange.setEnd(T.getLAngleLoc().getLocWithOffset(-1));
|
||||
}
|
||||
|
||||
if (const auto *ET = E.getTypePtr()) {
|
||||
if (const auto *TDT =
|
||||
dyn_cast<TypedefType>(ET->getNamedType().getTypePtr())) {
|
||||
MustInsertAfterLoc = TDT->getDecl()->getBeginLoc();
|
||||
} else if (auto *TD = ET->getAsTagDecl()) {
|
||||
MustInsertAfterLoc = TD->getBeginLoc();
|
||||
}
|
||||
}
|
||||
switch (T->getTypeLocClass()) {
|
||||
case TypeLoc::TemplateSpecialization: {
|
||||
auto TL = T->castAs<TemplateSpecializationTypeLoc>();
|
||||
QualifierToRemove = TL.getQualifierLoc();
|
||||
if (!QualifierToRemove)
|
||||
break;
|
||||
SpelledNameRange = TL.getTemplateNameLoc();
|
||||
if (auto *TD = TL.getTypePtr()->getTemplateName().getAsTemplateDecl(
|
||||
/*IgnoreDeduced=*/true))
|
||||
MustInsertAfterLoc = TD->getBeginLoc();
|
||||
break;
|
||||
}
|
||||
case TypeLoc::Enum:
|
||||
case TypeLoc::Record:
|
||||
case TypeLoc::InjectedClassName: {
|
||||
auto TL = T->castAs<TagTypeLoc>();
|
||||
QualifierToRemove = TL.getQualifierLoc();
|
||||
if (!QualifierToRemove)
|
||||
break;
|
||||
SpelledNameRange = TL.getNameLoc();
|
||||
MustInsertAfterLoc = TL.getOriginalDecl()->getBeginLoc();
|
||||
break;
|
||||
}
|
||||
case TypeLoc::Typedef: {
|
||||
auto TL = T->castAs<TypedefTypeLoc>();
|
||||
QualifierToRemove = TL.getQualifierLoc();
|
||||
if (!QualifierToRemove)
|
||||
break;
|
||||
SpelledNameRange = TL.getNameLoc();
|
||||
MustInsertAfterLoc = TL.getDecl()->getBeginLoc();
|
||||
break;
|
||||
}
|
||||
case TypeLoc::UnresolvedUsing: {
|
||||
auto TL = T->castAs<UnresolvedUsingTypeLoc>();
|
||||
QualifierToRemove = TL.getQualifierLoc();
|
||||
if (!QualifierToRemove)
|
||||
break;
|
||||
SpelledNameRange = TL.getNameLoc();
|
||||
MustInsertAfterLoc = TL.getDecl()->getBeginLoc();
|
||||
break;
|
||||
}
|
||||
case TypeLoc::Using: {
|
||||
auto TL = T->castAs<UsingTypeLoc>();
|
||||
QualifierToRemove = TL.getQualifierLoc();
|
||||
if (!QualifierToRemove)
|
||||
break;
|
||||
SpelledNameRange = TL.getNameLoc();
|
||||
MustInsertAfterLoc = TL.getDecl()->getBeginLoc();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (QualifierToRemove)
|
||||
SpelledNameRange.setBegin(QualifierToRemove.getBeginLoc());
|
||||
}
|
||||
if (!QualifierToRemove ||
|
||||
// FIXME: This only supports removing qualifiers that are made up of just
|
||||
// namespace names. If qualifier contains a type, we could take the
|
||||
// longest namespace prefix and remove that.
|
||||
!QualifierToRemove.getNestedNameSpecifier()->getAsNamespace() ||
|
||||
QualifierToRemove.getNestedNameSpecifier().getKind() !=
|
||||
NestedNameSpecifier::Kind::Namespace ||
|
||||
// Respect user config.
|
||||
isNamespaceForbidden(Inputs, *QualifierToRemove.getNestedNameSpecifier()))
|
||||
isNamespaceForbidden(Inputs, QualifierToRemove.getNestedNameSpecifier()))
|
||||
return false;
|
||||
// Macros are difficult. We only want to offer code action when what's spelled
|
||||
// under the cursor is a namespace qualifier. If it's a macro that expands to
|
||||
@ -384,7 +417,7 @@ Expected<Tweak::Effect> AddUsing::apply(const Selection &Inputs) {
|
||||
llvm::raw_string_ostream UsingTextStream(UsingText);
|
||||
UsingTextStream << "using ";
|
||||
if (InsertionPoint->AlwaysFullyQualify &&
|
||||
!isFullyQualified(QualifierToRemove.getNestedNameSpecifier()))
|
||||
!QualifierToRemove.getNestedNameSpecifier().isFullyQualified())
|
||||
UsingTextStream << "::";
|
||||
UsingTextStream << QualifierToSpell << SpelledName << ";"
|
||||
<< InsertionPoint->Suffix;
|
||||
|
@ -362,7 +362,7 @@ struct NewFunction {
|
||||
SourceLocation DefinitionPoint;
|
||||
std::optional<SourceLocation> ForwardDeclarationPoint;
|
||||
const CXXRecordDecl *EnclosingClass = nullptr;
|
||||
const NestedNameSpecifier *DefinitionQualifier = nullptr;
|
||||
NestedNameSpecifier DefinitionQualifier = std::nullopt;
|
||||
const DeclContext *SemanticDC = nullptr;
|
||||
const DeclContext *SyntacticDC = nullptr;
|
||||
const DeclContext *ForwardDeclarationSyntacticDC = nullptr;
|
||||
@ -455,13 +455,12 @@ std::string NewFunction::renderQualifiers() const {
|
||||
}
|
||||
|
||||
std::string NewFunction::renderDeclarationName(FunctionDeclKind K) const {
|
||||
if (DefinitionQualifier == nullptr || K != OutOfLineDefinition) {
|
||||
if (!DefinitionQualifier || K != OutOfLineDefinition)
|
||||
return Name;
|
||||
}
|
||||
|
||||
std::string QualifierName;
|
||||
llvm::raw_string_ostream Oss(QualifierName);
|
||||
DefinitionQualifier->print(Oss, *LangOpts);
|
||||
DefinitionQualifier.print(Oss, *LangOpts);
|
||||
return llvm::formatv("{0}{1}", QualifierName, Name);
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ bool PopulateSwitch::prepare(const Selection &Sel) {
|
||||
EnumT = Cond->getType().getCanonicalType()->getAsAdjusted<EnumType>();
|
||||
if (!EnumT)
|
||||
return false;
|
||||
EnumD = EnumT->getDecl();
|
||||
EnumD = EnumT->getOriginalDecl();
|
||||
if (!EnumD || EnumD->isDependentType())
|
||||
return false;
|
||||
|
||||
|
@ -421,7 +421,7 @@ TEST(ClangdAST, GetQualification) {
|
||||
{
|
||||
R"cpp(
|
||||
namespace ns1 { namespace ns2 { void Foo(); } }
|
||||
void insert(); // ns2::Foo
|
||||
void insert(); // ns1::ns2::Foo
|
||||
namespace ns1 {
|
||||
void insert(); // ns2::Foo
|
||||
namespace ns2 {
|
||||
@ -429,7 +429,7 @@ TEST(ClangdAST, GetQualification) {
|
||||
}
|
||||
}
|
||||
)cpp",
|
||||
{"ns2::", "ns2::", ""},
|
||||
{"ns1::ns2::", "ns2::", ""},
|
||||
{"ns1::"},
|
||||
},
|
||||
{
|
||||
@ -531,7 +531,8 @@ TEST(ClangdAST, PrintType) {
|
||||
ASSERT_EQ(InsertionPoints.size(), Case.Types.size());
|
||||
for (size_t I = 0, E = InsertionPoints.size(); I != E; ++I) {
|
||||
const auto *DC = InsertionPoints[I];
|
||||
EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC),
|
||||
EXPECT_EQ(printType(AST.getASTContext().getTypeDeclType(TargetDecl), *DC,
|
||||
/*Placeholder=*/"", /*FullyQualify=*/true),
|
||||
Case.Types[I]);
|
||||
}
|
||||
}
|
||||
|
@ -72,15 +72,14 @@ declaration: Namespace - root
|
||||
expression: BinaryOperator - +
|
||||
expression: ImplicitCast - LValueToRValue
|
||||
expression: DeclRef - x
|
||||
specifier: TypeSpec
|
||||
specifier: Type
|
||||
type: Record - S
|
||||
expression: ImplicitCast - LValueToRValue
|
||||
expression: Member - x
|
||||
expression: CXXBindTemporary
|
||||
expression: CXXTemporaryObject - S
|
||||
type: Elaborated
|
||||
type: Record - S
|
||||
specifier: Namespace - root::
|
||||
type: Record - S
|
||||
)"},
|
||||
{R"cpp(
|
||||
namespace root {
|
||||
@ -104,14 +103,13 @@ declaration: Namespace - root
|
||||
expression: BinaryOperator - +
|
||||
expression: ImplicitCast - LValueToRValue
|
||||
expression: DeclRef - x
|
||||
specifier: TypeSpec
|
||||
specifier: Type
|
||||
type: Record - S
|
||||
expression: ImplicitCast - LValueToRValue
|
||||
expression: Member - x
|
||||
expression: CXXTemporaryObject - S
|
||||
type: Elaborated
|
||||
type: Record - S
|
||||
specifier: Namespace - root::
|
||||
type: Record - S
|
||||
)"},
|
||||
{R"cpp(
|
||||
namespace root {
|
||||
@ -138,7 +136,7 @@ declaration: Namespace - root
|
||||
type: Builtin - unsigned int
|
||||
statement: Return
|
||||
expression: DependentScopeDeclRef - value
|
||||
specifier: TypeSpec
|
||||
specifier: Type
|
||||
type: TemplateTypeParm - T
|
||||
)"},
|
||||
{R"cpp(
|
||||
@ -154,8 +152,7 @@ declaration: Var - root
|
||||
expression: DeclRef - operator+
|
||||
expression: MaterializeTemporary - lvalue
|
||||
expression: CXXTemporaryObject - Foo
|
||||
type: Elaborated
|
||||
type: Record - Foo
|
||||
type: Record - Foo
|
||||
expression: IntegerLiteral - 42
|
||||
)"},
|
||||
{R"cpp(
|
||||
|
@ -992,7 +992,7 @@ TEST_F(TargetDeclTest, DependentTypes) {
|
||||
)cpp";
|
||||
EXPECT_DECLS("DependentNameTypeLoc", "struct B");
|
||||
|
||||
// Heuristic resolution of dependent type name which doesn't get a TypeLoc
|
||||
// Heuristic resolution of dependent type name within a NestedNameSpecifierLoc
|
||||
Code = R"cpp(
|
||||
template <typename>
|
||||
struct A { struct B { struct C {}; }; };
|
||||
@ -1000,7 +1000,7 @@ TEST_F(TargetDeclTest, DependentTypes) {
|
||||
template <typename T>
|
||||
void foo(typename A<T>::[[B]]::C);
|
||||
)cpp";
|
||||
EXPECT_DECLS("NestedNameSpecifierLoc", "struct B");
|
||||
EXPECT_DECLS("DependentNameTypeLoc", "struct B");
|
||||
|
||||
// Heuristic resolution of dependent type name whose qualifier is also
|
||||
// dependent
|
||||
|
@ -2894,7 +2894,7 @@ TEST(Hover, All) {
|
||||
)cpp",
|
||||
[](HoverInfo &HI) {
|
||||
HI.Name = "this";
|
||||
HI.Definition = "const Foo<T> *";
|
||||
HI.Definition = "const ns::Foo<T> *";
|
||||
}},
|
||||
{
|
||||
R"cpp(// this expr for specialization class
|
||||
@ -2910,7 +2910,7 @@ TEST(Hover, All) {
|
||||
)cpp",
|
||||
[](HoverInfo &HI) {
|
||||
HI.Name = "this";
|
||||
HI.Definition = "Foo<int> *";
|
||||
HI.Definition = "ns::Foo<int> *";
|
||||
}},
|
||||
{
|
||||
R"cpp(// this expr for partial specialization struct
|
||||
@ -2926,7 +2926,7 @@ TEST(Hover, All) {
|
||||
)cpp",
|
||||
[](HoverInfo &HI) {
|
||||
HI.Name = "this";
|
||||
HI.Definition = "const Foo<int, F> *";
|
||||
HI.Definition = "const ns::Foo<int, F> *";
|
||||
}},
|
||||
{
|
||||
R"cpp(
|
||||
@ -3046,8 +3046,8 @@ TEST(Hover, All) {
|
||||
HI.Kind = index::SymbolKind::Function;
|
||||
HI.NamespaceScope = "";
|
||||
HI.Definition = "MyRect foobar()";
|
||||
HI.Type = {"MyRect ()", "MyRect ()"};
|
||||
HI.ReturnType = {"MyRect", "MyRect"};
|
||||
HI.Type = {"MyRect ()", "struct MyRect ()"};
|
||||
HI.ReturnType = {"MyRect", "struct MyRect"};
|
||||
HI.Parameters.emplace();
|
||||
}},
|
||||
{R"cpp(
|
||||
|
@ -1295,14 +1295,7 @@ TEST(TypeHints, NoQualifiers) {
|
||||
}
|
||||
}
|
||||
)cpp",
|
||||
ExpectedHint{": S1", "x"},
|
||||
// FIXME: We want to suppress scope specifiers
|
||||
// here because we are into the whole
|
||||
// brevity thing, but the ElaboratedType
|
||||
// printer does not honor the SuppressScope
|
||||
// flag by design, so we need to extend the
|
||||
// PrintingPolicy to support this use case.
|
||||
ExpectedHint{": S2::Inner<int>", "y"});
|
||||
ExpectedHint{": S1", "x"}, ExpectedHint{": Inner<int>", "y"});
|
||||
}
|
||||
|
||||
TEST(TypeHints, Lambda) {
|
||||
|
@ -121,7 +121,9 @@ TEST(QualityTests, SymbolRelevanceSignalExtraction) {
|
||||
|
||||
SymbolRelevanceSignals Relevance;
|
||||
Relevance.merge(CodeCompletionResult(&findDecl(AST, "deprecated"),
|
||||
/*Priority=*/42, nullptr, false,
|
||||
/*Priority=*/42,
|
||||
/*Qualifier=*/std::nullopt,
|
||||
/*QualifierIsInformative=*/false,
|
||||
/*Accessible=*/false));
|
||||
EXPECT_EQ(Relevance.NameMatch, SymbolRelevanceSignals().NameMatch);
|
||||
EXPECT_TRUE(Relevance.Forbidden);
|
||||
@ -487,13 +489,15 @@ TEST(QualityTests, ItemWithFixItsRankedDown) {
|
||||
auto AST = Header.build();
|
||||
|
||||
SymbolRelevanceSignals RelevanceWithFixIt;
|
||||
RelevanceWithFixIt.merge(CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr,
|
||||
false, true, {FixItHint{}}));
|
||||
RelevanceWithFixIt.merge(CodeCompletionResult(
|
||||
&findDecl(AST, "x"), /*Priority=*/0, /*Qualifier=*/std::nullopt,
|
||||
/*QualifierIsInformative=*/false, /*Accessible=*/true, {FixItHint{}}));
|
||||
EXPECT_TRUE(RelevanceWithFixIt.NeedsFixIts);
|
||||
|
||||
SymbolRelevanceSignals RelevanceWithoutFixIt;
|
||||
RelevanceWithoutFixIt.merge(
|
||||
CodeCompletionResult(&findDecl(AST, "x"), 0, nullptr, false, true, {}));
|
||||
RelevanceWithoutFixIt.merge(CodeCompletionResult(
|
||||
&findDecl(AST, "x"), /*Priority=*/0, /*Qualifier=*/std::nullopt,
|
||||
/*QualifierIsInformative=*/false, /*Accessible=*/true, {}));
|
||||
EXPECT_FALSE(RelevanceWithoutFixIt.NeedsFixIts);
|
||||
|
||||
EXPECT_LT(RelevanceWithFixIt.evaluateHeuristics(),
|
||||
|
@ -104,9 +104,9 @@ TEST(SelectionTest, CommonAncestor) {
|
||||
{
|
||||
R"cpp(
|
||||
template <typename T>
|
||||
int x = [[T::^U::]]ccc();
|
||||
int x = T::[[^U]]::ccc();
|
||||
)cpp",
|
||||
"NestedNameSpecifierLoc",
|
||||
"DependentNameTypeLoc",
|
||||
},
|
||||
{
|
||||
R"cpp(
|
||||
|
@ -60,14 +60,10 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
|
||||
NamedDecl *getMemberProvider(QualType Base) {
|
||||
if (Base->isPointerType())
|
||||
return getMemberProvider(Base->getPointeeType());
|
||||
// Unwrap the sugar ElaboratedType.
|
||||
if (const auto *ElTy = dyn_cast<ElaboratedType>(Base))
|
||||
return getMemberProvider(ElTy->getNamedType());
|
||||
|
||||
if (const auto *TT = dyn_cast<TypedefType>(Base))
|
||||
return TT->getDecl();
|
||||
if (const auto *UT = dyn_cast<UsingType>(Base))
|
||||
return UT->getFoundDecl();
|
||||
return UT->getDecl();
|
||||
// A heuristic: to resolve a template type to **only** its template name.
|
||||
// We're only using this method for the base type of MemberExpr, in general
|
||||
// the template provides the member, and the critical case `unique_ptr<Foo>`
|
||||
@ -135,16 +131,14 @@ public:
|
||||
}
|
||||
|
||||
bool qualifierIsNamespaceOrNone(DeclRefExpr *DRE) {
|
||||
const auto *Qual = DRE->getQualifier();
|
||||
if (!Qual)
|
||||
NestedNameSpecifier Qual = DRE->getQualifier();
|
||||
switch (Qual.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
return true;
|
||||
switch (Qual->getKind()) {
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::Global:
|
||||
return true;
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
case NestedNameSpecifier::Super:
|
||||
case NestedNameSpecifier::Identifier:
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
return false;
|
||||
}
|
||||
llvm_unreachable("Unknown value for NestedNameSpecifierKind");
|
||||
@ -341,17 +335,17 @@ public:
|
||||
}
|
||||
|
||||
bool VisitUsingTypeLoc(UsingTypeLoc TL) {
|
||||
reportType(TL.getNameLoc(), TL.getFoundDecl());
|
||||
reportType(TL.getNameLoc(), TL.getDecl());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTagTypeLoc(TagTypeLoc TTL) {
|
||||
reportType(TTL.getNameLoc(), TTL.getDecl());
|
||||
reportType(TTL.getNameLoc(), TTL.getOriginalDecl());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VisitTypedefTypeLoc(TypedefTypeLoc TTL) {
|
||||
reportType(TTL.getNameLoc(), TTL.getTypedefNameDecl());
|
||||
reportType(TTL.getNameLoc(), TTL.getDecl());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,6 @@ FROMMACRO
|
||||
class X15 : public CopyableAlias2 {
|
||||
X15(const X15 &other) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: calling a base constructor
|
||||
// CHECK-FIXES: X15(const X15 &other) : Copyable5(other) {}
|
||||
};
|
||||
|
||||
class X16 : public NonCopyable {
|
||||
|
@ -69,14 +69,14 @@ template<typename T>
|
||||
T qux(T Generic) {
|
||||
async::Future<Units> PendingA = acquireUnits();
|
||||
auto PendingB = acquireUnits();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'async::Future<Units>') [bugprone-unused-local-non-trivial-variable]
|
||||
async::Future<Units> MustBeUsed;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: unused local variable 'MustBeUsed' of type 'async::Future<Units>' [bugprone-unused-local-non-trivial-variable]
|
||||
PendingA.get();
|
||||
async::Future<T> TemplateType;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable]
|
||||
a::Future<T> AliasTemplateType;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<T>') [bugprone-unused-local-non-trivial-variable]
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'async::Future<T>') [bugprone-unused-local-non-trivial-variable]
|
||||
[[maybe_unused]] async::Future<Units> MaybeUnused;
|
||||
return Generic;
|
||||
}
|
||||
@ -86,7 +86,7 @@ async::Future<int> Global;
|
||||
int bar(int Num) {
|
||||
a::Future<Units> PendingA = acquireUnits();
|
||||
a::Future<Units> PendingB = acquireUnits(); // not used at all, unused variable not fired because of destructor side effect
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'Future<Units>') [bugprone-unused-local-non-trivial-variable]
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'PendingB' of type 'a::Future<Units>' (aka 'async::Future<Units>') [bugprone-unused-local-non-trivial-variable]
|
||||
auto Num2 = PendingA.get();
|
||||
auto Num3 = qux(Num);
|
||||
async::Ptr<a::Future<Units>> Shared = async::Ptr<a::Future<Units>>(acquireUnits());
|
||||
|
@ -43,25 +43,25 @@ template <class T>
|
||||
class allocator {};
|
||||
|
||||
void simple(const std::vector<const char> &v, std::deque<const short> *d) {
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:24: warning: container using std::allocator<const T> is a deprecated libc++ extension; remove const for compatibility with other standard libraries
|
||||
// CHECK-MESSAGES: [[#@LINE-2]]:52: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:19: warning: container using std::allocator<const T> is a deprecated libc++ extension; remove const for compatibility with other standard libraries
|
||||
// CHECK-MESSAGES: [[#@LINE-2]]:47: warning: container
|
||||
std::list<const long> l;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
|
||||
std::multiset<int *const> ms;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
std::set<const std::hash<int>> s;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
std::unordered_multiset<int *const> ums;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
std::unordered_set<const int> us;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
|
||||
absl::flat_hash_set<const int> fhs;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:9: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
|
||||
using my_vector = std::vector<const int>;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:26: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:21: warning: container
|
||||
my_vector v1;
|
||||
using my_vector2 = my_vector;
|
||||
|
||||
@ -76,7 +76,7 @@ void simple(const std::vector<const char> &v, std::deque<const short> *d) {
|
||||
template <class T>
|
||||
void temp1() {
|
||||
std::vector<const T> v;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
|
||||
std::vector<T> neg1;
|
||||
std::forward_list<const T> neg2;
|
||||
@ -87,7 +87,7 @@ template <class T>
|
||||
void temp2() {
|
||||
// Match std::vector<const dependent> for the uninstantiated temp2.
|
||||
std::vector<const T> v;
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:8: warning: container
|
||||
// CHECK-MESSAGES: [[#@LINE-1]]:3: warning: container
|
||||
|
||||
std::vector<T> neg1;
|
||||
std::forward_list<const T> neg2;
|
||||
|
@ -63,7 +63,7 @@ class TestType(unittest.TestCase):
|
||||
self.assertIsNotNone(fields[1].translation_unit)
|
||||
self.assertEqual(fields[1].spelling, "b")
|
||||
self.assertFalse(fields[1].type.is_const_qualified())
|
||||
self.assertEqual(fields[1].type.kind, TypeKind.ELABORATED)
|
||||
self.assertEqual(fields[1].type.kind, TypeKind.TYPEDEF)
|
||||
self.assertEqual(fields[1].type.get_canonical().kind, TypeKind.INT)
|
||||
self.assertEqual(fields[1].type.get_declaration().spelling, "I")
|
||||
self.assertEqual(fields[1].type.get_typedef_name(), "I")
|
||||
|
@ -70,12 +70,16 @@ ABI Changes in This Version
|
||||
|
||||
AST Dumping Potentially Breaking Changes
|
||||
----------------------------------------
|
||||
- How nested name specifiers are dumped and printed changes, keeping track of clang AST changes.
|
||||
|
||||
Clang Frontend Potentially Breaking Changes
|
||||
-------------------------------------------
|
||||
|
||||
Clang Python Bindings Potentially Breaking Changes
|
||||
--------------------------------------------------
|
||||
- TypeKind ``ELABORATED`` is not used anymore, per clang AST changes removing
|
||||
ElaboratedTypes. The value becomes unused, and all the existing users should
|
||||
expect the former underlying type to be reported instead.
|
||||
|
||||
What's New in Clang |release|?
|
||||
==============================
|
||||
@ -111,13 +115,13 @@ Non-comprehensive list of changes in this release
|
||||
-------------------------------------------------
|
||||
- Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``.
|
||||
|
||||
- Trapping UBSan (e.g. ``-fsanitize-trap=undefined``) now emits a string describing the reason for
|
||||
trapping into the generated debug info. This feature allows debuggers (e.g. LLDB) to display
|
||||
the reason for trapping if the trap is reached. The string is currently encoded in the debug
|
||||
info as an artificial frame that claims to be inlined at the trap location. The function used
|
||||
for the artificial frame is an artificial function whose name encodes the reason for trapping.
|
||||
The encoding used is currently the same as ``__builtin_verbose_trap`` but might change in the future.
|
||||
This feature is enabled by default but can be disabled by compiling with
|
||||
- Trapping UBSan (e.g. ``-fsanitize-trap=undefined``) now emits a string describing the reason for
|
||||
trapping into the generated debug info. This feature allows debuggers (e.g. LLDB) to display
|
||||
the reason for trapping if the trap is reached. The string is currently encoded in the debug
|
||||
info as an artificial frame that claims to be inlined at the trap location. The function used
|
||||
for the artificial frame is an artificial function whose name encodes the reason for trapping.
|
||||
The encoding used is currently the same as ``__builtin_verbose_trap`` but might change in the future.
|
||||
This feature is enabled by default but can be disabled by compiling with
|
||||
``-fno-sanitize-annotate-debug-info-traps``.
|
||||
|
||||
New Compiler Flags
|
||||
@ -143,7 +147,7 @@ Improvements to Clang's diagnostics
|
||||
Moved the warning for a missing (though implied) attribute on a redeclaration into this group.
|
||||
Added a new warning in this group for the case where the attribute is missing/implicit on
|
||||
an override of a virtual method.
|
||||
- Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right
|
||||
- Fixed fix-it hint for fold expressions. Clang now correctly places the suggested right
|
||||
parenthesis when diagnosing malformed fold expressions. (#GH151787)
|
||||
|
||||
Improvements to Clang's time-trace
|
||||
@ -187,6 +191,9 @@ Bug Fixes to C++ Support
|
||||
|
||||
Bug Fixes to AST Handling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
- Fix incorrect name qualifiers applied to alias CTAD. (#GH136624)
|
||||
- Fixed ElaboratedTypes appearing within NestedNameSpecifier, which was not a
|
||||
legal representation. This is fixed because ElaboratedTypes don't exist anymore. (#GH43179) (#GH68670) (#GH92757)
|
||||
|
||||
Miscellaneous Bug Fixes
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -256,6 +263,8 @@ Fixed Point Support in Clang
|
||||
|
||||
AST Matchers
|
||||
------------
|
||||
- Removed elaboratedType matchers, and related nested name specifier changes,
|
||||
following the corresponding changes in the clang AST.
|
||||
- Ensure ``hasBitWidth`` doesn't crash on bit widths that are dependent on template
|
||||
parameters.
|
||||
|
||||
@ -280,7 +289,7 @@ New features
|
||||
|
||||
Crash and bug fixes
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
- Fixed a crash in the static analyzer that when the expression in an
|
||||
- Fixed a crash in the static analyzer that when the expression in an
|
||||
``[[assume(expr)]]`` attribute was enclosed in parentheses. (#GH151529)
|
||||
|
||||
Improvements
|
||||
|
@ -15,7 +15,7 @@
|
||||
#define LLVM_CLANG_AST_ASTCONCEPT_H
|
||||
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/NestedNameSpecifierBase.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/UnsignedOrNone.h"
|
||||
@ -177,12 +177,7 @@ public:
|
||||
|
||||
SourceLocation getLocation() const { return getConceptNameLoc(); }
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY {
|
||||
// Note that if the qualifier is null the template KW must also be null.
|
||||
if (auto QualifierLoc = getNestedNameSpecifierLoc())
|
||||
return QualifierLoc.getBeginLoc();
|
||||
return getConceptNameInfo().getBeginLoc();
|
||||
}
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY;
|
||||
|
||||
SourceLocation getEndLoc() const LLVM_READONLY {
|
||||
return getTemplateArgsAsWritten() &&
|
||||
|
@ -233,10 +233,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&>
|
||||
TemplateSpecializationTypes;
|
||||
mutable llvm::FoldingSet<ParenType> ParenTypes{GeneralTypesLog2InitSize};
|
||||
mutable llvm::FoldingSet<TagTypeFoldingSetPlaceholder> TagTypes;
|
||||
mutable llvm::FoldingSet<FoldingSetPlaceholder<UnresolvedUsingType>>
|
||||
UnresolvedUsingTypes;
|
||||
mutable llvm::FoldingSet<UsingType> UsingTypes;
|
||||
mutable llvm::FoldingSet<TypedefType> TypedefTypes;
|
||||
mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes{
|
||||
GeneralTypesLog2InitSize};
|
||||
mutable llvm::FoldingSet<FoldingSetPlaceholder<TypedefType>> TypedefTypes;
|
||||
mutable llvm::FoldingSet<DependentNameType> DependentNameTypes;
|
||||
mutable llvm::DenseMap<llvm::FoldingSetNodeID,
|
||||
DependentTemplateSpecializationType *>
|
||||
@ -282,11 +283,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
llvm::to_underlying(PredefinedSugarType::Kind::Last) + 1>
|
||||
PredefinedSugarTypes{};
|
||||
|
||||
/// The set of nested name specifiers.
|
||||
/// Internal storage for NestedNameSpecifiers.
|
||||
///
|
||||
/// This set is managed by the NestedNameSpecifier class.
|
||||
mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers;
|
||||
mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr;
|
||||
mutable llvm::FoldingSet<NamespaceAndPrefixStorage>
|
||||
NamespaceAndPrefixStorages;
|
||||
|
||||
/// A cache mapping from RecordDecls to ASTRecordLayouts.
|
||||
///
|
||||
@ -1386,8 +1387,6 @@ private:
|
||||
/// Return a type with extended qualifiers.
|
||||
QualType getExtQualType(const Type *Base, Qualifiers Quals) const;
|
||||
|
||||
QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const;
|
||||
|
||||
QualType getPipeType(QualType T, bool ReadOnly) const;
|
||||
|
||||
public:
|
||||
@ -1630,7 +1629,7 @@ public:
|
||||
|
||||
/// Return the uniqued reference to the type for a member pointer to
|
||||
/// the specified type in the specified nested name.
|
||||
QualType getMemberPointerType(QualType T, NestedNameSpecifier *Qualifier,
|
||||
QualType getMemberPointerType(QualType T, NestedNameSpecifier Qualifier,
|
||||
const CXXRecordDecl *Cls) const;
|
||||
|
||||
/// Return a non-unique reference to the type for a variable array of
|
||||
@ -1767,34 +1766,53 @@ private:
|
||||
bool IsCanon = false) const;
|
||||
|
||||
public:
|
||||
QualType getTypeDeclType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier Qualifier,
|
||||
const TypeDecl *Decl) const;
|
||||
|
||||
/// Return the unique reference to the type for the specified type
|
||||
/// declaration.
|
||||
QualType getTypeDeclType(const TypeDecl *Decl,
|
||||
const TypeDecl *PrevDecl = nullptr) const {
|
||||
assert(Decl && "Passed null for Decl param");
|
||||
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
|
||||
QualType getTypeDeclType(const TypeDecl *Decl) const;
|
||||
|
||||
if (PrevDecl) {
|
||||
assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl");
|
||||
Decl->TypeForDecl = PrevDecl->TypeForDecl;
|
||||
return QualType(PrevDecl->TypeForDecl, 0);
|
||||
}
|
||||
/// Use the normal 'getFooBarType' constructors to obtain these types.
|
||||
QualType getTypeDeclType(const TagDecl *) const = delete;
|
||||
QualType getTypeDeclType(const TypedefDecl *) const = delete;
|
||||
QualType getTypeDeclType(const TypeAliasDecl *) const = delete;
|
||||
QualType getTypeDeclType(const UnresolvedUsingTypenameDecl *) const = delete;
|
||||
|
||||
return getTypeDeclTypeSlow(Decl);
|
||||
}
|
||||
CanQualType getCanonicalTypeDeclType(const TypeDecl *TD) const;
|
||||
|
||||
QualType getUsingType(const UsingShadowDecl *Found,
|
||||
QualType Underlying) const;
|
||||
QualType getUsingType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier Qualifier, const UsingShadowDecl *D,
|
||||
QualType UnderlyingType = QualType()) const;
|
||||
|
||||
/// Return the unique reference to the type for the specified
|
||||
/// typedef-name decl.
|
||||
QualType getTypedefType(const TypedefNameDecl *Decl,
|
||||
QualType Underlying = QualType()) const;
|
||||
/// FIXME: TypeMatchesDeclOrNone is a workaround for a serialization issue:
|
||||
/// The decl underlying type might still not be available.
|
||||
QualType getTypedefType(
|
||||
ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier,
|
||||
const TypedefNameDecl *Decl, QualType UnderlyingType = QualType(),
|
||||
std::optional<bool> TypeMatchesDeclOrNone = std::nullopt) const;
|
||||
|
||||
QualType getRecordType(const RecordDecl *Decl) const;
|
||||
CanQualType getCanonicalTagType(const TagDecl *TD) const;
|
||||
QualType getTagType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier Qualifier, const TagDecl *TD,
|
||||
bool OwnsTag) const;
|
||||
|
||||
QualType getEnumType(const EnumDecl *Decl) const;
|
||||
private:
|
||||
UnresolvedUsingType *getUnresolvedUsingTypeInternal(
|
||||
ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier,
|
||||
const UnresolvedUsingTypenameDecl *D, void *InsertPos,
|
||||
const Type *CanonicalType) const;
|
||||
|
||||
TagType *getTagTypeInternal(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier Qualifier, const TagDecl *Tag,
|
||||
bool OwnsTag, bool IsInjected,
|
||||
const Type *CanonicalType,
|
||||
bool WithFoldingSetNode) const;
|
||||
|
||||
public:
|
||||
/// Compute BestType and BestPromotionType for an enum based on the highest
|
||||
/// number of negative and positive bits of its elements.
|
||||
/// Returns true if enum width is too large.
|
||||
@ -1843,10 +1861,11 @@ public:
|
||||
return MembersRepresentableByInt;
|
||||
}
|
||||
|
||||
QualType
|
||||
getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const;
|
||||
|
||||
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
|
||||
CanQualType
|
||||
getCanonicalUnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) const;
|
||||
QualType getUnresolvedUsingType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier Qualifier,
|
||||
const UnresolvedUsingTypenameDecl *D) const;
|
||||
|
||||
QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
|
||||
QualType equivalentType,
|
||||
@ -1886,18 +1905,20 @@ public:
|
||||
TemplateName T, ArrayRef<TemplateArgument> CanonicalArgs) const;
|
||||
|
||||
QualType
|
||||
getTemplateSpecializationType(TemplateName T,
|
||||
getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T,
|
||||
ArrayRef<TemplateArgument> SpecifiedArgs,
|
||||
ArrayRef<TemplateArgument> CanonicalArgs,
|
||||
QualType Underlying = QualType()) const;
|
||||
|
||||
QualType
|
||||
getTemplateSpecializationType(TemplateName T,
|
||||
getTemplateSpecializationType(ElaboratedTypeKeyword Keyword, TemplateName T,
|
||||
ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
|
||||
ArrayRef<TemplateArgument> CanonicalArgs,
|
||||
QualType Canon = QualType()) const;
|
||||
|
||||
TypeSourceInfo *getTemplateSpecializationTypeInfo(
|
||||
ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc,
|
||||
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc,
|
||||
TemplateName T, SourceLocation TLoc,
|
||||
const TemplateArgumentListInfo &SpecifiedArgs,
|
||||
ArrayRef<TemplateArgument> CanonicalArgs,
|
||||
@ -1908,11 +1929,8 @@ public:
|
||||
QualType getMacroQualifiedType(QualType UnderlyingTy,
|
||||
const IdentifierInfo *MacroII) const;
|
||||
|
||||
QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS, QualType NamedType,
|
||||
TagDecl *OwnedTagDecl = nullptr) const;
|
||||
QualType getDependentNameType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS,
|
||||
NestedNameSpecifier NNS,
|
||||
const IdentifierInfo *Name) const;
|
||||
|
||||
QualType getDependentTemplateSpecializationType(
|
||||
@ -1999,21 +2017,17 @@ public:
|
||||
QualType getUnconstrainedType(QualType T) const;
|
||||
|
||||
/// C++17 deduced class template specialization type.
|
||||
QualType getDeducedTemplateSpecializationType(TemplateName Template,
|
||||
QualType getDeducedTemplateSpecializationType(ElaboratedTypeKeyword Keyword,
|
||||
TemplateName Template,
|
||||
QualType DeducedType,
|
||||
bool IsDependent) const;
|
||||
|
||||
private:
|
||||
QualType getDeducedTemplateSpecializationTypeInternal(TemplateName Template,
|
||||
QualType DeducedType,
|
||||
bool IsDependent,
|
||||
QualType Canon) const;
|
||||
QualType getDeducedTemplateSpecializationTypeInternal(
|
||||
ElaboratedTypeKeyword Keyword, TemplateName Template,
|
||||
QualType DeducedType, bool IsDependent, QualType Canon) const;
|
||||
|
||||
public:
|
||||
/// Return the unique reference to the type for the specified TagDecl
|
||||
/// (struct/union/class/enum) decl.
|
||||
QualType getTagDeclType(const TagDecl *Decl) const;
|
||||
|
||||
/// Return the unique type for "size_t" (C99 7.17), defined in
|
||||
/// <stddef.h>.
|
||||
///
|
||||
@ -2089,7 +2103,9 @@ public:
|
||||
/// if it hasn't yet been built.
|
||||
QualType getRawCFConstantStringType() const {
|
||||
if (CFConstantStringTypeDecl)
|
||||
return getTypedefType(CFConstantStringTypeDecl);
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt,
|
||||
CFConstantStringTypeDecl);
|
||||
return QualType();
|
||||
}
|
||||
void setCFConstantStringType(QualType T);
|
||||
@ -2186,10 +2202,11 @@ public:
|
||||
}
|
||||
#include "clang/Basic/BuiltinTemplates.inc"
|
||||
|
||||
/// Retrieve the Objective-C "instancetype" type, if already known;
|
||||
/// otherwise, returns a NULL type;
|
||||
/// Retrieve the Objective-C "instancetype" type.
|
||||
QualType getObjCInstanceType() {
|
||||
return getTypeDeclType(getObjCInstanceTypeDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt,
|
||||
getObjCInstanceTypeDecl());
|
||||
}
|
||||
|
||||
/// Retrieve the typedef declaration corresponding to the Objective-C
|
||||
@ -2202,7 +2219,8 @@ public:
|
||||
/// Retrieve the C FILE type.
|
||||
QualType getFILEType() const {
|
||||
if (FILEDecl)
|
||||
return getTypeDeclType(FILEDecl);
|
||||
return getTypeDeclType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, FILEDecl);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
@ -2214,7 +2232,8 @@ public:
|
||||
/// Retrieve the C jmp_buf type.
|
||||
QualType getjmp_bufType() const {
|
||||
if (jmp_bufDecl)
|
||||
return getTypeDeclType(jmp_bufDecl);
|
||||
return getTypeDeclType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, jmp_bufDecl);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
@ -2226,7 +2245,8 @@ public:
|
||||
/// Retrieve the C sigjmp_buf type.
|
||||
QualType getsigjmp_bufType() const {
|
||||
if (sigjmp_bufDecl)
|
||||
return getTypeDeclType(sigjmp_bufDecl);
|
||||
return getTypeDeclType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, sigjmp_bufDecl);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
@ -2238,12 +2258,13 @@ public:
|
||||
/// Retrieve the C ucontext_t type.
|
||||
QualType getucontext_tType() const {
|
||||
if (ucontext_tDecl)
|
||||
return getTypeDeclType(ucontext_tDecl);
|
||||
return getTypeDeclType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, ucontext_tDecl);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
/// The result type of logical operations, '<', '>', '!=', etc.
|
||||
QualType getLogicalOperationType() const {
|
||||
CanQualType getLogicalOperationType() const {
|
||||
return getLangOpts().CPlusPlus ? BoolTy : IntTy;
|
||||
}
|
||||
|
||||
@ -2308,7 +2329,8 @@ public:
|
||||
/// This is set up lazily, by Sema. \c id is always a (typedef for a)
|
||||
/// pointer type, a pointer to a struct.
|
||||
QualType getObjCIdType() const {
|
||||
return getTypeDeclType(getObjCIdDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, getObjCIdDecl());
|
||||
}
|
||||
|
||||
/// Retrieve the typedef corresponding to the predefined 'SEL' type
|
||||
@ -2318,7 +2340,8 @@ public:
|
||||
/// Retrieve the type that corresponds to the predefined Objective-C
|
||||
/// 'SEL' type.
|
||||
QualType getObjCSelType() const {
|
||||
return getTypeDeclType(getObjCSelDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, getObjCSelDecl());
|
||||
}
|
||||
|
||||
PointerAuthQualifier getObjCMemberSelTypePtrAuth();
|
||||
@ -2332,7 +2355,8 @@ public:
|
||||
/// This is set up lazily, by Sema. \c Class is always a (typedef for a)
|
||||
/// pointer type, a pointer to a struct.
|
||||
QualType getObjCClassType() const {
|
||||
return getTypeDeclType(getObjCClassDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, getObjCClassDecl());
|
||||
}
|
||||
|
||||
/// Retrieve the Objective-C class declaration corresponding to
|
||||
@ -2351,7 +2375,8 @@ public:
|
||||
|
||||
/// type of 'BOOL' type.
|
||||
QualType getBOOLType() const {
|
||||
return getTypeDeclType(getBOOLDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, getBOOLDecl());
|
||||
}
|
||||
|
||||
/// Retrieve the type of the Objective-C \c Protocol class.
|
||||
@ -2365,7 +2390,8 @@ public:
|
||||
|
||||
/// Retrieve the type of the \c __builtin_va_list type.
|
||||
QualType getBuiltinVaListType() const {
|
||||
return getTypeDeclType(getBuiltinVaListDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, getBuiltinVaListDecl());
|
||||
}
|
||||
|
||||
/// Retrieve the C type declaration corresponding to the predefined
|
||||
@ -2379,16 +2405,17 @@ public:
|
||||
|
||||
/// Retrieve the type of the \c __builtin_ms_va_list type.
|
||||
QualType getBuiltinMSVaListType() const {
|
||||
return getTypeDeclType(getBuiltinMSVaListDecl());
|
||||
return getTypedefType(ElaboratedTypeKeyword::None,
|
||||
/*Qualifier=*/std::nullopt, getBuiltinMSVaListDecl());
|
||||
}
|
||||
|
||||
/// Retrieve the implicitly-predeclared 'struct _GUID' declaration.
|
||||
TagDecl *getMSGuidTagDecl() const { return MSGuidTagDecl; }
|
||||
|
||||
/// Retrieve the implicitly-predeclared 'struct _GUID' type.
|
||||
QualType getMSGuidType() const {
|
||||
CanQualType getMSGuidType() const {
|
||||
assert(MSGuidTagDecl && "asked for GUID type but MS extensions disabled");
|
||||
return getTagDeclType(MSGuidTagDecl);
|
||||
return getCanonicalTagType(MSGuidTagDecl);
|
||||
}
|
||||
|
||||
/// Retrieve the implicitly-predeclared 'struct type_info' declaration.
|
||||
@ -2477,7 +2504,7 @@ public:
|
||||
UnresolvedSetIterator End) const;
|
||||
TemplateName getAssumedTemplateName(DeclarationName Name) const;
|
||||
|
||||
TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS,
|
||||
TemplateName getQualifiedTemplateName(NestedNameSpecifier Qualifier,
|
||||
bool TemplateKeyword,
|
||||
TemplateName Template) const;
|
||||
TemplateName
|
||||
@ -2919,32 +2946,6 @@ public:
|
||||
/// Determine if two types are similar, ignoring only CVR qualifiers.
|
||||
bool hasCvrSimilarType(QualType T1, QualType T2);
|
||||
|
||||
/// Retrieves the "canonical" nested name specifier for a
|
||||
/// given nested name specifier.
|
||||
///
|
||||
/// The canonical nested name specifier is a nested name specifier
|
||||
/// that uniquely identifies a type or namespace within the type
|
||||
/// system. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// namespace N {
|
||||
/// struct S {
|
||||
/// template<typename T> struct X { typename T* type; };
|
||||
/// };
|
||||
/// }
|
||||
///
|
||||
/// template<typename T> struct Y {
|
||||
/// typename N::S::X<T>::type member;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, the nested-name-specifier for N::S::X<T>:: will be
|
||||
/// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined
|
||||
/// by declarations in the type system and the canonical type for
|
||||
/// the template type parameter 'T' is template-param-0-0.
|
||||
NestedNameSpecifier *
|
||||
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
|
||||
|
||||
/// Retrieves the default calling convention for the current context.
|
||||
///
|
||||
/// The context's default calling convention may differ from the current
|
||||
@ -3158,7 +3159,7 @@ public:
|
||||
mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
|
||||
FunctionProtoType::ExceptionSpecInfo ESI2,
|
||||
SmallVectorImpl<QualType> &ExceptionTypeStorage,
|
||||
bool AcceptDependent);
|
||||
bool AcceptDependent) const;
|
||||
|
||||
// For two "same" types, return a type which has
|
||||
// the common sugar between them. If Unqualified is true,
|
||||
@ -3166,7 +3167,7 @@ public:
|
||||
// The result will drop the qualifiers which do not occur
|
||||
// in both types.
|
||||
QualType getCommonSugaredType(QualType X, QualType Y,
|
||||
bool Unqualified = false);
|
||||
bool Unqualified = false) const;
|
||||
|
||||
private:
|
||||
// Helper for integer ordering
|
||||
@ -3184,23 +3185,11 @@ public:
|
||||
bool propertyTypesAreCompatible(QualType, QualType);
|
||||
bool typesAreBlockPointerCompatible(QualType, QualType);
|
||||
|
||||
bool isObjCIdType(QualType T) const {
|
||||
if (const auto *ET = dyn_cast<ElaboratedType>(T))
|
||||
T = ET->getNamedType();
|
||||
return T == getObjCIdType();
|
||||
}
|
||||
bool isObjCIdType(QualType T) const { return T == getObjCIdType(); }
|
||||
|
||||
bool isObjCClassType(QualType T) const {
|
||||
if (const auto *ET = dyn_cast<ElaboratedType>(T))
|
||||
T = ET->getNamedType();
|
||||
return T == getObjCClassType();
|
||||
}
|
||||
bool isObjCClassType(QualType T) const { return T == getObjCClassType(); }
|
||||
|
||||
bool isObjCSelType(QualType T) const {
|
||||
if (const auto *ET = dyn_cast<ElaboratedType>(T))
|
||||
T = ET->getNamedType();
|
||||
return T == getObjCSelType();
|
||||
}
|
||||
bool isObjCSelType(QualType T) const { return T == getObjCSelType(); }
|
||||
|
||||
bool ObjCQualifiedIdTypesAreCompatible(const ObjCObjectPointerType *LHS,
|
||||
const ObjCObjectPointerType *RHS,
|
||||
|
@ -404,7 +404,7 @@ class TypeSourceInfo;
|
||||
///
|
||||
/// \returns The equivalent nested-name-specifier in the "to"
|
||||
/// context, or the import error.
|
||||
llvm::Expected<NestedNameSpecifier *> Import(NestedNameSpecifier *FromNNS);
|
||||
llvm::Expected<NestedNameSpecifier> Import(NestedNameSpecifier FromNNS);
|
||||
|
||||
/// Import the given nested-name-specifier-loc from the "from"
|
||||
/// context into the "to" context.
|
||||
|
@ -394,12 +394,14 @@ public:
|
||||
}
|
||||
void VisitMemberPointerType(const MemberPointerType *T) {
|
||||
// FIXME: Provide a NestedNameSpecifier visitor.
|
||||
NestedNameSpecifier *Qualifier = T->getQualifier();
|
||||
if (NestedNameSpecifier::SpecifierKind K = Qualifier->getKind();
|
||||
K == NestedNameSpecifier::TypeSpec)
|
||||
Visit(Qualifier->getAsType());
|
||||
NestedNameSpecifier Qualifier = T->getQualifier();
|
||||
if (NestedNameSpecifier::Kind K = Qualifier.getKind();
|
||||
K == NestedNameSpecifier::Kind::Type)
|
||||
Visit(Qualifier.getAsType());
|
||||
if (T->isSugared())
|
||||
Visit(T->getMostRecentCXXRecordDecl()->getTypeForDecl());
|
||||
Visit(cast<MemberPointerType>(T->getCanonicalTypeUnqualified())
|
||||
->getQualifier()
|
||||
.getAsType());
|
||||
Visit(T->getPointeeType());
|
||||
}
|
||||
void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); }
|
||||
@ -510,7 +512,7 @@ public:
|
||||
}
|
||||
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
|
||||
// FIXME: Provide NestedNamespecifierLoc visitor.
|
||||
Visit(TL.getQualifierLoc().getTypeLoc());
|
||||
Visit(TL.getQualifierLoc().castAsTypeLoc());
|
||||
}
|
||||
void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
|
||||
Visit(TL.getSizeExpr());
|
||||
@ -772,17 +774,16 @@ public:
|
||||
}
|
||||
|
||||
void VisitUsingShadowDecl(const UsingShadowDecl *D) {
|
||||
if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl()))
|
||||
Visit(TD->getTypeForDecl());
|
||||
Visit(D->getTargetDecl());
|
||||
}
|
||||
|
||||
void VisitFriendDecl(const FriendDecl *D) {
|
||||
if (D->getFriendType()) {
|
||||
// Traverse any CXXRecordDecl owned by this type, since
|
||||
// it will not be in the parent context:
|
||||
if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>())
|
||||
if (auto *TD = ET->getOwnedTagDecl())
|
||||
Visit(TD);
|
||||
if (auto *TT = D->getFriendType()->getType()->getAs<TagType>())
|
||||
if (TT->isTagOwned())
|
||||
Visit(TT->getOriginalDecl());
|
||||
} else {
|
||||
Visit(D->getFriendDecl());
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ public:
|
||||
|
||||
/// For nodes which represent textual entities in the source code,
|
||||
/// return their SourceRange. For all other nodes, return SourceRange().
|
||||
SourceRange getSourceRange() const;
|
||||
SourceRange getSourceRange(bool IncludeQualifier = false) const;
|
||||
|
||||
/// @{
|
||||
/// Imposes an order on \c DynTypedNode.
|
||||
@ -336,9 +336,9 @@ public:
|
||||
NodeKind)) {
|
||||
auto NNSLA = getUnchecked<NestedNameSpecifierLoc>();
|
||||
auto NNSLB = Other.getUnchecked<NestedNameSpecifierLoc>();
|
||||
return std::make_pair(NNSLA.getNestedNameSpecifier(),
|
||||
return std::make_pair(NNSLA.getNestedNameSpecifier().getAsVoidPointer(),
|
||||
NNSLA.getOpaqueData()) <
|
||||
std::make_pair(NNSLB.getNestedNameSpecifier(),
|
||||
std::make_pair(NNSLB.getNestedNameSpecifier().getAsVoidPointer(),
|
||||
NNSLB.getOpaqueData());
|
||||
}
|
||||
|
||||
@ -393,8 +393,9 @@ public:
|
||||
if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(
|
||||
Val.NodeKind)) {
|
||||
auto NNSL = Val.getUnchecked<NestedNameSpecifierLoc>();
|
||||
return llvm::hash_combine(NNSL.getNestedNameSpecifier(),
|
||||
NNSL.getOpaqueData());
|
||||
return llvm::hash_combine(
|
||||
NNSL.getNestedNameSpecifier().getAsVoidPointer(),
|
||||
NNSL.getOpaqueData());
|
||||
}
|
||||
|
||||
assert(Val.getMemoizationData());
|
||||
@ -539,8 +540,8 @@ struct DynTypedNode::BaseConverter<
|
||||
: public DynCastPtrConverter<T, Attr> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {};
|
||||
struct DynTypedNode::BaseConverter<NestedNameSpecifier, void>
|
||||
: public ValueConverter<NestedNameSpecifier> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
|
@ -197,7 +197,7 @@ public:
|
||||
unsigned int_ = asImpl().readUInt32();
|
||||
Decl *decl = asImpl().template readDeclAs<Decl>();
|
||||
if (auto *recordDecl = dyn_cast<CXXRecordDecl>(decl))
|
||||
elemTy = getASTContext().getRecordType(recordDecl);
|
||||
elemTy = getASTContext().getCanonicalTagType(recordDecl);
|
||||
else
|
||||
elemTy = cast<ValueDecl>(decl)->getType();
|
||||
path.push_back(
|
||||
@ -252,39 +252,34 @@ public:
|
||||
return EffectConditionExpr{asImpl().readExprRef()};
|
||||
}
|
||||
|
||||
NestedNameSpecifier *readNestedNameSpecifier() {
|
||||
NestedNameSpecifier readNestedNameSpecifier() {
|
||||
auto &ctx = getASTContext();
|
||||
|
||||
// We build this up iteratively.
|
||||
NestedNameSpecifier *cur = nullptr;
|
||||
NestedNameSpecifier cur = std::nullopt;
|
||||
|
||||
uint32_t depth = asImpl().readUInt32();
|
||||
for (uint32_t i = 0; i != depth; ++i) {
|
||||
auto kind = asImpl().readNestedNameSpecifierKind();
|
||||
switch (kind) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
cur = NestedNameSpecifier::Create(ctx, cur,
|
||||
asImpl().readIdentifier());
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
cur =
|
||||
NestedNameSpecifier(ctx, asImpl().readNamespaceBaseDeclRef(), cur);
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Namespace:
|
||||
cur = NestedNameSpecifier::Create(ctx, cur,
|
||||
asImpl().readNamespaceBaseDeclRef());
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
assert(!cur);
|
||||
cur = NestedNameSpecifier(asImpl().readQualType().getTypePtr());
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
cur = NestedNameSpecifier::Create(ctx, cur,
|
||||
asImpl().readQualType().getTypePtr());
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
assert(!cur);
|
||||
cur = NestedNameSpecifier::getGlobal();
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Global:
|
||||
cur = NestedNameSpecifier::GlobalSpecifier(ctx);
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Super:
|
||||
cur = NestedNameSpecifier::SuperSpecifier(ctx,
|
||||
asImpl().readCXXRecordDeclRef());
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
assert(!cur);
|
||||
cur = NestedNameSpecifier(asImpl().readCXXRecordDeclRef());
|
||||
continue;
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
llvm_unreachable("unexpected null nested name specifier");
|
||||
}
|
||||
llvm_unreachable("bad nested name specifier kind");
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ public:
|
||||
const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer();
|
||||
if (const auto *recordDecl = dyn_cast<CXXRecordDecl>(baseOrMember)) {
|
||||
asImpl().writeDeclRef(recordDecl);
|
||||
elemTy = ctx.getRecordType(recordDecl);
|
||||
elemTy = ctx.getCanonicalTagType(recordDecl);
|
||||
} else {
|
||||
const auto *valueDecl = cast<ValueDecl>(baseOrMember);
|
||||
asImpl().writeDeclRef(valueDecl);
|
||||
@ -229,42 +229,43 @@ public:
|
||||
asImpl().writeExprRef(CE.getCondition());
|
||||
}
|
||||
|
||||
void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
|
||||
void writeNestedNameSpecifier(NestedNameSpecifier NNS) {
|
||||
// Nested name specifiers usually aren't too long. I think that 8 would
|
||||
// typically accommodate the vast majority.
|
||||
SmallVector<NestedNameSpecifier *, 8> nestedNames;
|
||||
SmallVector<NestedNameSpecifier, 8> nestedNames;
|
||||
|
||||
// Push each of the NNS's onto a stack for serialization in reverse order.
|
||||
while (NNS) {
|
||||
nestedNames.push_back(NNS);
|
||||
NNS = NNS->getPrefix();
|
||||
NNS = NNS.getKind() == NestedNameSpecifier::Kind::Namespace
|
||||
? NNS.getAsNamespaceAndPrefix().Prefix
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
asImpl().writeUInt32(nestedNames.size());
|
||||
while (!nestedNames.empty()) {
|
||||
NNS = nestedNames.pop_back_val();
|
||||
NestedNameSpecifier::SpecifierKind kind = NNS->getKind();
|
||||
NestedNameSpecifier::Kind kind = NNS.getKind();
|
||||
asImpl().writeNestedNameSpecifierKind(kind);
|
||||
switch (kind) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
asImpl().writeIdentifier(NNS->getAsIdentifier());
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
asImpl().writeNamespaceBaseDeclRef(
|
||||
NNS.getAsNamespaceAndPrefix().Namespace);
|
||||
continue;
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
asImpl().writeQualType(QualType(NNS.getAsType(), 0));
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Namespace:
|
||||
asImpl().writeNamespaceBaseDeclRef(NNS->getAsNamespace());
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
asImpl().writeQualType(QualType(NNS->getAsType(), 0));
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
// Don't need to write an associated value.
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Super:
|
||||
asImpl().writeDeclRef(NNS->getAsRecordDecl());
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
asImpl().writeDeclRef(NNS.getAsMicrosoftSuper());
|
||||
continue;
|
||||
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
llvm_unreachable("unexpected null nested name specifier");
|
||||
}
|
||||
llvm_unreachable("bad nested name specifier kind");
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ template<>
|
||||
struct CanProxyAdaptor<MemberPointerType>
|
||||
: public CanProxyBase<MemberPointerType> {
|
||||
LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier *, getQualifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier, getQualifier)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const CXXRecordDecl *,
|
||||
getMostRecentCXXRecordDecl)
|
||||
};
|
||||
@ -551,21 +551,18 @@ struct CanProxyAdaptor<UnaryTransformType>
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getOriginalDecl)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getOriginalDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields)
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> {
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined)
|
||||
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getOriginalDecl)
|
||||
};
|
||||
|
||||
template<>
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/ExternalASTSource.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/NestedNameSpecifierBase.h"
|
||||
#include "clang/AST/Redeclarable.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/AddressSpaces.h"
|
||||
@ -833,9 +833,9 @@ public:
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the name of this
|
||||
/// declaration, if it was present in the source.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier()
|
||||
: nullptr;
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
/// Retrieve the nested-name-specifier (with source-location
|
||||
@ -3528,8 +3528,14 @@ public:
|
||||
// check out ASTContext::getTypeDeclType or one of
|
||||
// ASTContext::getTypedefType, ASTContext::getRecordType, etc. if you
|
||||
// already know the specific kind of node this is.
|
||||
const Type *getTypeForDecl() const { return TypeForDecl; }
|
||||
void setTypeForDecl(const Type *TD) { TypeForDecl = TD; }
|
||||
const Type *getTypeForDecl() const {
|
||||
assert(!isa<TagDecl>(this));
|
||||
return TypeForDecl;
|
||||
}
|
||||
void setTypeForDecl(const Type *TD) {
|
||||
assert(!isa<TagDecl>(this));
|
||||
TypeForDecl = TD;
|
||||
}
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY { return LocStart; }
|
||||
void setLocStart(SourceLocation L) { LocStart = L; }
|
||||
@ -3635,6 +3641,10 @@ public:
|
||||
return isTransparentTagSlow();
|
||||
}
|
||||
|
||||
// These types are created lazily, use the ASTContext methods to obtain them.
|
||||
const Type *getTypeForDecl() const = delete;
|
||||
void setTypeForDecl(const Type *TD) = delete;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) {
|
||||
@ -3754,14 +3764,6 @@ protected:
|
||||
/// True if this decl is currently being defined.
|
||||
void setBeingDefined(bool V = true) { TagDeclBits.IsBeingDefined = V; }
|
||||
|
||||
/// Indicates whether it is possible for declarations of this kind
|
||||
/// to have an out-of-date definition.
|
||||
///
|
||||
/// This option is only enabled when modules are enabled.
|
||||
void setMayHaveOutOfDateDef(bool V = true) {
|
||||
TagDeclBits.MayHaveOutOfDateDef = V;
|
||||
}
|
||||
|
||||
public:
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
@ -3842,12 +3844,6 @@ public:
|
||||
TagDeclBits.IsFreeStanding = isFreeStanding;
|
||||
}
|
||||
|
||||
/// Indicates whether it is possible for declarations of this kind
|
||||
/// to have an out-of-date definition.
|
||||
///
|
||||
/// This option is only enabled when modules are enabled.
|
||||
bool mayHaveOutOfDateDef() const { return TagDeclBits.MayHaveOutOfDateDef; }
|
||||
|
||||
/// Whether this declaration declares a type that is
|
||||
/// dependent, i.e., a type that somehow depends on template
|
||||
/// parameters.
|
||||
@ -3888,6 +3884,19 @@ public:
|
||||
/// the struct/union/class/enum.
|
||||
TagDecl *getDefinition() const;
|
||||
|
||||
TagDecl *getDefinitionOrSelf() const {
|
||||
if (TagDecl *Def = getDefinition())
|
||||
return Def;
|
||||
return const_cast<TagDecl *>(this);
|
||||
}
|
||||
|
||||
/// Determines whether this entity is in the process of being defined.
|
||||
bool isEntityBeingDefined() const {
|
||||
if (const TagDecl *Def = getDefinition())
|
||||
return Def->isBeingDefined();
|
||||
return false;
|
||||
}
|
||||
|
||||
StringRef getKindName() const {
|
||||
return TypeWithKeyword::getTagTypeKindName(getTagKind());
|
||||
}
|
||||
@ -3934,9 +3943,9 @@ public:
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the name of this
|
||||
/// declaration, if it was present in the source.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier()
|
||||
: nullptr;
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
/// Retrieve the nested-name-specifier (with source-location
|
||||
@ -3958,6 +3967,10 @@ public:
|
||||
return getExtInfo()->TemplParamLists[i];
|
||||
}
|
||||
|
||||
// These types are created lazily, use the ASTContext methods to obtain them.
|
||||
const Type *getTypeForDecl() const = delete;
|
||||
void setTypeForDecl(const Type *TD) = delete;
|
||||
|
||||
using TypeDecl::printName;
|
||||
void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
|
||||
|
||||
@ -4087,6 +4100,10 @@ public:
|
||||
return cast_or_null<EnumDecl>(TagDecl::getDefinition());
|
||||
}
|
||||
|
||||
EnumDecl *getDefinitionOrSelf() const {
|
||||
return cast_or_null<EnumDecl>(TagDecl::getDefinitionOrSelf());
|
||||
}
|
||||
|
||||
static EnumDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id, EnumDecl *PrevDecl,
|
||||
@ -4469,6 +4486,10 @@ public:
|
||||
return cast_or_null<RecordDecl>(TagDecl::getDefinition());
|
||||
}
|
||||
|
||||
RecordDecl *getDefinitionOrSelf() const {
|
||||
return cast_or_null<RecordDecl>(TagDecl::getDefinitionOrSelf());
|
||||
}
|
||||
|
||||
/// Returns whether this record is a union, or contains (at any nesting level)
|
||||
/// a union member. This is used by CMSE to warn about possible information
|
||||
/// leaks.
|
||||
@ -5299,6 +5320,8 @@ void Redeclarable<decl_type>::setPreviousDecl(decl_type *PrevDecl) {
|
||||
/// We use this function to break a cycle between the inline definitions in
|
||||
/// Type.h and Decl.h.
|
||||
inline bool IsEnumDeclComplete(EnumDecl *ED) {
|
||||
if (const auto *Def = ED->getDefinition())
|
||||
return Def->isComplete();
|
||||
return ED->isComplete();
|
||||
}
|
||||
|
||||
|
@ -410,9 +410,6 @@ protected:
|
||||
|
||||
virtual ~Decl();
|
||||
|
||||
/// Update a potentially out-of-date declaration.
|
||||
void updateOutOfDate(IdentifierInfo &II) const;
|
||||
|
||||
Linkage getCachedLinkage() const {
|
||||
return static_cast<Linkage>(CacheValidAndLinkage);
|
||||
}
|
||||
@ -625,6 +622,12 @@ public:
|
||||
|
||||
void setReferenced(bool R = true) { Referenced = R; }
|
||||
|
||||
/// When doing manipulations which might change the computed linkage,
|
||||
/// such as changing the DeclContext after the declaration has already been
|
||||
/// used, invalidating the cache will make sure its linkage will be
|
||||
/// recomputed.
|
||||
void invalidateCachedLinkage() { setCachedLinkage(Linkage::Invalid); }
|
||||
|
||||
/// Whether this declaration is a top-level declaration (function,
|
||||
/// global variable, etc.) that is lexically inside an objc container
|
||||
/// definition.
|
||||
@ -1564,13 +1567,6 @@ protected:
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
uint64_t IsFreeStanding : 1;
|
||||
|
||||
/// Indicates whether it is possible for declarations of this kind
|
||||
/// to have an out-of-date definition.
|
||||
///
|
||||
/// This option is only enabled when modules are enabled.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
uint64_t MayHaveOutOfDateDef : 1;
|
||||
|
||||
/// Has the full definition of this type been required by a use somewhere in
|
||||
/// the TU.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
|
@ -545,20 +545,6 @@ public:
|
||||
return const_cast<CXXRecordDecl*>(this)->getMostRecentDecl();
|
||||
}
|
||||
|
||||
CXXRecordDecl *getMostRecentNonInjectedDecl() {
|
||||
CXXRecordDecl *Recent = getMostRecentDecl();
|
||||
while (Recent->isInjectedClassName()) {
|
||||
// FIXME: Does injected class name need to be in the redeclarations chain?
|
||||
assert(Recent->getPreviousDecl());
|
||||
Recent = Recent->getPreviousDecl();
|
||||
}
|
||||
return Recent;
|
||||
}
|
||||
|
||||
const CXXRecordDecl *getMostRecentNonInjectedDecl() const {
|
||||
return const_cast<CXXRecordDecl*>(this)->getMostRecentNonInjectedDecl();
|
||||
}
|
||||
|
||||
CXXRecordDecl *getDefinition() const {
|
||||
// We only need an update if we don't already know which
|
||||
// declaration is the definition.
|
||||
@ -566,13 +552,18 @@ public:
|
||||
return DD ? DD->Definition : nullptr;
|
||||
}
|
||||
|
||||
CXXRecordDecl *getDefinitionOrSelf() const {
|
||||
if (auto *Def = getDefinition())
|
||||
return Def;
|
||||
return const_cast<CXXRecordDecl *>(this);
|
||||
}
|
||||
|
||||
bool hasDefinition() const { return DefinitionData || dataPtr(); }
|
||||
|
||||
static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
IdentifierInfo *Id,
|
||||
CXXRecordDecl *PrevDecl = nullptr,
|
||||
bool DelayTypeCreation = false);
|
||||
CXXRecordDecl *PrevDecl = nullptr);
|
||||
static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC,
|
||||
TypeSourceInfo *Info, SourceLocation Loc,
|
||||
unsigned DependencyKind, bool IsGeneric,
|
||||
@ -1903,6 +1894,20 @@ public:
|
||||
/// \endcode
|
||||
bool isInjectedClassName() const;
|
||||
|
||||
/// Determines whether this declaration has is canonically of an injected
|
||||
/// class type. These are non-instantiated class template patterns, which can
|
||||
/// be used from within the class template itself. For example:
|
||||
///
|
||||
/// \code
|
||||
/// template<class T> struct C {
|
||||
/// C *t; // Here `C *` is a pointer to an injected class type.
|
||||
/// };
|
||||
/// \endcode
|
||||
bool hasInjectedClassType() const;
|
||||
|
||||
CanQualType
|
||||
getCanonicalTemplateSpecializationType(const ASTContext &Ctx) const;
|
||||
|
||||
// Determine whether this type is an Interface Like type for
|
||||
// __interface inheritance purposes.
|
||||
bool isInterfaceLike() const;
|
||||
@ -3131,7 +3136,7 @@ public:
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the
|
||||
/// name of the namespace.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3252,7 +3257,7 @@ public:
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the
|
||||
/// name of the namespace.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3614,7 +3619,7 @@ public:
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the name.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3804,13 +3809,11 @@ public:
|
||||
/// The source location of the 'enum' keyword.
|
||||
SourceLocation getEnumLoc() const { return EnumLocation; }
|
||||
void setEnumLoc(SourceLocation L) { EnumLocation = L; }
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return getQualifierLoc().getNestedNameSpecifier();
|
||||
}
|
||||
NestedNameSpecifierLoc getQualifierLoc() const {
|
||||
if (auto ETL = EnumType->getTypeLoc().getAs<ElaboratedTypeLoc>())
|
||||
return ETL.getQualifierLoc();
|
||||
return NestedNameSpecifierLoc();
|
||||
return getEnumTypeLoc().getPrefix();
|
||||
}
|
||||
// Returns the "qualifier::Name" part as a TypeLoc.
|
||||
TypeLoc getEnumTypeLoc() const {
|
||||
@ -3970,7 +3973,7 @@ public:
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the name.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -4060,7 +4063,7 @@ public:
|
||||
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the name.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
|
@ -643,6 +643,9 @@ public:
|
||||
/// from the explicitly-specified bound.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
|
||||
using TypeDecl::getTypeForDecl;
|
||||
using TypeDecl::setTypeForDecl;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == ObjCTypeParam; }
|
||||
|
@ -1898,14 +1898,14 @@ public:
|
||||
void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool Qualified) const override;
|
||||
|
||||
// FIXME: This is broken. CXXRecordDecl::getMostRecentDecl() returns a
|
||||
// different "most recent" declaration from this function for the same
|
||||
// declaration, because we don't override getMostRecentDeclImpl(). But
|
||||
// it's not clear that we should override that, because the most recent
|
||||
// declaration as a CXXRecordDecl sometimes is the injected-class-name.
|
||||
ClassTemplateSpecializationDecl *getMostRecentDecl() {
|
||||
return cast<ClassTemplateSpecializationDecl>(
|
||||
getMostRecentNonInjectedDecl());
|
||||
CXXRecordDecl::getMostRecentDecl());
|
||||
}
|
||||
|
||||
ClassTemplateSpecializationDecl *getDefinitionOrSelf() const {
|
||||
return cast<ClassTemplateSpecializationDecl>(
|
||||
CXXRecordDecl::getDefinitionOrSelf());
|
||||
}
|
||||
|
||||
/// Retrieve the template that this specialization specializes.
|
||||
@ -2123,10 +2123,13 @@ class ClassTemplatePartialSpecializationDecl
|
||||
llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
|
||||
InstantiatedFromMember;
|
||||
|
||||
mutable CanQualType CanonInjectedTST;
|
||||
|
||||
ClassTemplatePartialSpecializationDecl(
|
||||
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, TemplateParameterList *Params,
|
||||
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
|
||||
CanQualType CanonInjectedTST,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
ClassTemplatePartialSpecializationDecl(ASTContext &C)
|
||||
@ -2143,7 +2146,7 @@ public:
|
||||
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
|
||||
SourceLocation StartLoc, SourceLocation IdLoc,
|
||||
TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
|
||||
ArrayRef<TemplateArgument> Args, QualType CanonInjectedType,
|
||||
ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
|
||||
ClassTemplatePartialSpecializationDecl *PrevDecl);
|
||||
|
||||
static ClassTemplatePartialSpecializationDecl *
|
||||
@ -2160,12 +2163,6 @@ public:
|
||||
return TemplateParams;
|
||||
}
|
||||
|
||||
/// Get the template argument list of the template parameter list.
|
||||
ArrayRef<TemplateArgument>
|
||||
getInjectedTemplateArgs(const ASTContext &Context) const {
|
||||
return getTemplateParameters()->getInjectedTemplateArgs(Context);
|
||||
}
|
||||
|
||||
/// \brief All associated constraints of this partial specialization,
|
||||
/// including the requires clause and any constraints derived from
|
||||
/// constrained-parameters.
|
||||
@ -2247,14 +2244,10 @@ public:
|
||||
return First->InstantiatedFromMember.setInt(true);
|
||||
}
|
||||
|
||||
/// Retrieves the injected specialization type for this partial
|
||||
/// specialization. This is not the same as the type-decl-type for
|
||||
/// this partial specialization, which is an InjectedClassNameType.
|
||||
QualType getInjectedSpecializationType() const {
|
||||
assert(getTypeForDecl() && "partial specialization has no type set!");
|
||||
return cast<InjectedClassNameType>(getTypeForDecl())
|
||||
->getInjectedSpecializationType();
|
||||
}
|
||||
/// Retrieves the canonical injected specialization type for this partial
|
||||
/// specialization.
|
||||
CanQualType
|
||||
getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const;
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
@ -2289,8 +2282,8 @@ protected:
|
||||
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>
|
||||
PartialSpecializations;
|
||||
|
||||
/// The injected-class-name type for this class template.
|
||||
QualType InjectedClassNameType;
|
||||
/// The Injected Template Specialization Type for this declaration.
|
||||
CanQualType CanonInjectedTST;
|
||||
|
||||
Common() = default;
|
||||
};
|
||||
@ -2427,7 +2420,7 @@ public:
|
||||
findPartialSpecInstantiatedFromMember(
|
||||
ClassTemplatePartialSpecializationDecl *D);
|
||||
|
||||
/// Retrieve the template specialization type of the
|
||||
/// Retrieve the canonical template specialization type of the
|
||||
/// injected-class-name for this class template.
|
||||
///
|
||||
/// The injected-class-name for a class template \c X is \c
|
||||
@ -2441,7 +2434,8 @@ public:
|
||||
/// typedef array this_type; // "array" is equivalent to "array<T, N>"
|
||||
/// };
|
||||
/// \endcode
|
||||
QualType getInjectedClassNameSpecialization();
|
||||
CanQualType
|
||||
getCanonicalInjectedSpecializationType(const ASTContext &Ctx) const;
|
||||
|
||||
using spec_iterator = SpecIterator<ClassTemplateSpecializationDecl>;
|
||||
using spec_range = llvm::iterator_range<spec_iterator>;
|
||||
|
@ -293,7 +293,7 @@ inline TypeDependence toSemanticDependence(TypeDependence D) {
|
||||
}
|
||||
|
||||
inline NestedNameSpecifierDependence
|
||||
toNestedNameSpecifierDependendence(TypeDependence D) {
|
||||
toNestedNameSpecifierDependence(TypeDependence D) {
|
||||
return Dependence(D).nestedNameSpecifier();
|
||||
}
|
||||
|
||||
|
@ -134,8 +134,7 @@ public:
|
||||
/// Recursively visit a C++ nested-name-specifier.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
virtual bool
|
||||
TraverseNestedNameSpecifier(MaybeConst<NestedNameSpecifier> *NNS);
|
||||
virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
|
||||
|
||||
/// Recursively visit a C++ nested-name-specifier with location
|
||||
/// information.
|
||||
@ -181,14 +180,14 @@ public:
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true
|
||||
/// otherwise (including when the argument is a Null type).
|
||||
virtual bool TraverseType(QualType T);
|
||||
virtual bool TraverseType(QualType T, bool TraverseQualifier = true);
|
||||
|
||||
/// Recursively visit a type with location, by dispatching to
|
||||
/// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true
|
||||
/// otherwise (including when the argument is a Null type location).
|
||||
virtual bool TraverseTypeLoc(TypeLoc TL);
|
||||
virtual bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true);
|
||||
|
||||
/// Recursively visit an Objective-C protocol reference with location
|
||||
/// information.
|
||||
@ -273,7 +272,8 @@ public:
|
||||
#define ABSTRACT_TYPE(CLASS, BASE)
|
||||
#define TYPE(CLASS, BASE) \
|
||||
bool WalkUpFrom##CLASS##Type(MaybeConst<CLASS##Type> *T); \
|
||||
virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T);
|
||||
virtual bool Traverse##CLASS##Type(MaybeConst<CLASS##Type> *T, \
|
||||
bool TraverseQualifier = true);
|
||||
#include "clang/AST/TypeNodes.inc"
|
||||
|
||||
#define TYPE(CLASS, BASE) \
|
||||
@ -283,7 +283,8 @@ public:
|
||||
// TypeLocs.
|
||||
#define ABSTRACT_TYPELOC(CLASS, BASE)
|
||||
#define TYPELOC(CLASS, BASE) \
|
||||
virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
|
||||
virtual bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, \
|
||||
bool TraverseQualifier);
|
||||
#include "clang/AST/TypeLocNodes.def"
|
||||
|
||||
#define TYPELOC(CLASS, BASE) \
|
||||
|
@ -1369,7 +1369,7 @@ public:
|
||||
|
||||
/// If the name was qualified, retrieves the nested-name-specifier
|
||||
/// that precedes the name. Otherwise, returns NULL.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return getQualifierLoc().getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3398,7 +3398,7 @@ public:
|
||||
/// If the member name was qualified, retrieves the
|
||||
/// nested-name-specifier that precedes the member name. Otherwise, returns
|
||||
/// NULL.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return getQualifierLoc().getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
|
@ -2781,7 +2781,7 @@ public:
|
||||
/// If the member name was qualified, retrieves the
|
||||
/// nested-name-specifier that precedes the member name. Otherwise, returns
|
||||
/// null.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3222,7 +3222,7 @@ public:
|
||||
SourceLocation getNameLoc() const { return NameInfo.getLoc(); }
|
||||
|
||||
/// Fetches the nested-name qualifier, if one was given.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3540,7 +3540,7 @@ public:
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies this
|
||||
/// declaration.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
@ -3955,7 +3955,7 @@ public:
|
||||
}
|
||||
|
||||
/// Retrieve the nested-name-specifier that qualifies the member name.
|
||||
NestedNameSpecifier *getQualifier() const {
|
||||
NestedNameSpecifier getQualifier() const {
|
||||
return QualifierLoc.getNestedNameSpecifier();
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,6 @@ public:
|
||||
void VisitInjectedClassNameType(const InjectedClassNameType *ICNT);
|
||||
void VisitObjCInterfaceType(const ObjCInterfaceType *OIT);
|
||||
void VisitPackExpansionType(const PackExpansionType *PET);
|
||||
void VisitElaboratedType(const ElaboratedType *ET);
|
||||
void VisitMacroQualifiedType(const MacroQualifiedType *MQT);
|
||||
void VisitMemberPointerType(const MemberPointerType *MPT);
|
||||
|
||||
|
@ -6,507 +6,266 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the NestedNameSpecifier class, which represents
|
||||
// a C++ nested-name-specifier.
|
||||
// This file completes the definition of the NestedNameSpecifier class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
|
||||
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H
|
||||
|
||||
#include "clang/AST/DependenceFlags.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/NestedNameSpecifierBase.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class IdentifierInfo;
|
||||
class LangOptions;
|
||||
class NamespaceBaseDecl;
|
||||
struct PrintingPolicy;
|
||||
class Type;
|
||||
class TypeLoc;
|
||||
auto NestedNameSpecifier::getKind() const -> Kind {
|
||||
if (!isStoredKind()) {
|
||||
switch (getFlagKind()) {
|
||||
case FlagKind::Null:
|
||||
return Kind::Null;
|
||||
case FlagKind::Global:
|
||||
return Kind::Global;
|
||||
case FlagKind::Invalid:
|
||||
llvm_unreachable("use of invalid NestedNameSpecifier");
|
||||
}
|
||||
llvm_unreachable("unhandled FlagKind");
|
||||
}
|
||||
switch (auto [K, Ptr] = getStored(); K) {
|
||||
case StoredKind::Type:
|
||||
return Kind::Type;
|
||||
case StoredKind::NamespaceWithGlobal:
|
||||
case StoredKind::NamespaceWithNamespace:
|
||||
return Kind::Namespace;
|
||||
case StoredKind::NamespaceOrSuper:
|
||||
switch (static_cast<const Decl *>(Ptr)->getKind()) {
|
||||
case Decl::Namespace:
|
||||
case Decl::NamespaceAlias:
|
||||
return Kind::Namespace;
|
||||
case Decl::CXXRecord:
|
||||
case Decl::ClassTemplateSpecialization:
|
||||
case Decl::ClassTemplatePartialSpecialization:
|
||||
return Kind::MicrosoftSuper;
|
||||
default:
|
||||
llvm_unreachable("unexpected decl kind");
|
||||
}
|
||||
}
|
||||
llvm_unreachable("unknown StoredKind");
|
||||
}
|
||||
|
||||
/// Represents a C++ nested name specifier, such as
|
||||
/// "\::std::vector<int>::".
|
||||
///
|
||||
/// C++ nested name specifiers are the prefixes to qualified
|
||||
/// names. For example, "foo::" in "foo::x" is a nested name
|
||||
/// specifier. Nested name specifiers are made up of a sequence of
|
||||
/// specifiers, each of which can be a namespace, type, identifier
|
||||
/// (for dependent names), decltype specifier, or the global specifier ('::').
|
||||
/// The last two specifiers can only appear at the start of a
|
||||
/// nested-namespace-specifier.
|
||||
class NestedNameSpecifier : public llvm::FoldingSetNode {
|
||||
/// Enumeration describing
|
||||
enum StoredSpecifierKind {
|
||||
StoredIdentifier = 0,
|
||||
StoredDecl = 1,
|
||||
StoredTypeSpec = 2
|
||||
};
|
||||
NestedNameSpecifier::NestedNameSpecifier(const Type *T)
|
||||
: NestedNameSpecifier({StoredKind::Type, T}) {
|
||||
assert(getKind() == Kind::Type);
|
||||
}
|
||||
|
||||
/// The nested name specifier that precedes this nested name
|
||||
/// specifier.
|
||||
///
|
||||
/// The pointer is the nested-name-specifier that precedes this
|
||||
/// one. The integer stores one of the first four values of type
|
||||
/// SpecifierKind.
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 2, StoredSpecifierKind> Prefix;
|
||||
auto NestedNameSpecifier::MakeNamespacePtrKind(
|
||||
const ASTContext &Ctx, const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix) -> PtrKind {
|
||||
switch (Prefix.getKind()) {
|
||||
case Kind::Null:
|
||||
return {StoredKind::NamespaceOrSuper, Namespace};
|
||||
case Kind::Global:
|
||||
return {StoredKind::NamespaceWithGlobal, Namespace};
|
||||
case Kind::Namespace:
|
||||
return {StoredKind::NamespaceWithNamespace,
|
||||
MakeNamespaceAndPrefixStorage(Ctx, Namespace, Prefix)};
|
||||
case Kind::MicrosoftSuper:
|
||||
case Kind::Type:
|
||||
llvm_unreachable("invalid prefix for namespace");
|
||||
}
|
||||
llvm_unreachable("unhandled kind");
|
||||
}
|
||||
|
||||
/// The last component in the nested name specifier, which
|
||||
/// can be an identifier, a declaration, or a type.
|
||||
///
|
||||
/// When the pointer is NULL, this specifier represents the global
|
||||
/// specifier '::'. Otherwise, the pointer is one of
|
||||
/// IdentifierInfo*, Namespace*, or Type*, depending on the kind of
|
||||
/// specifier as encoded within the prefix.
|
||||
void* Specifier = nullptr;
|
||||
/// Builds a nested name specifier that names a namespace.
|
||||
NestedNameSpecifier::NestedNameSpecifier(const ASTContext &Ctx,
|
||||
const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix)
|
||||
: NestedNameSpecifier(MakeNamespacePtrKind(Ctx, Namespace, Prefix)) {
|
||||
assert(getKind() == Kind::Namespace);
|
||||
}
|
||||
|
||||
public:
|
||||
/// The kind of specifier that completes this nested name
|
||||
/// specifier.
|
||||
enum SpecifierKind {
|
||||
/// An identifier, stored as an IdentifierInfo*.
|
||||
Identifier,
|
||||
|
||||
/// A namespace-like entity, stored as a NamespaceBaseDecl*.
|
||||
Namespace,
|
||||
|
||||
/// A type, stored as a Type*.
|
||||
TypeSpec,
|
||||
|
||||
/// The global specifier '::'. There is no stored value.
|
||||
Global,
|
||||
|
||||
/// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of
|
||||
/// the class it appeared in.
|
||||
Super
|
||||
};
|
||||
|
||||
private:
|
||||
/// Builds the global specifier.
|
||||
NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {}
|
||||
|
||||
/// Copy constructor used internally to clone nested name
|
||||
/// specifiers.
|
||||
NestedNameSpecifier(const NestedNameSpecifier &Other) = default;
|
||||
|
||||
/// Either find or insert the given nested name specifier
|
||||
/// mockup in the given context.
|
||||
static NestedNameSpecifier *FindOrInsert(const ASTContext &Context,
|
||||
const NestedNameSpecifier &Mockup);
|
||||
|
||||
public:
|
||||
NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete;
|
||||
|
||||
/// Builds a specifier combining a prefix and an identifier.
|
||||
///
|
||||
/// The prefix must be dependent, since nested name specifiers
|
||||
/// referencing an identifier are only permitted when the identifier
|
||||
/// cannot be resolved.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
const IdentifierInfo *II);
|
||||
|
||||
/// Builds a nested name specifier that names a namespace or namespace alias.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
NestedNameSpecifier *Prefix,
|
||||
const NamespaceBaseDecl *NS);
|
||||
|
||||
/// Builds a nested name specifier that names a type.
|
||||
static NestedNameSpecifier *
|
||||
Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const Type *T);
|
||||
|
||||
/// Builds a specifier that consists of just an identifier.
|
||||
///
|
||||
/// The nested-name-specifier is assumed to be dependent, but has no
|
||||
/// prefix because the prefix is implied by something outside of the
|
||||
/// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
|
||||
/// type.
|
||||
static NestedNameSpecifier *Create(const ASTContext &Context,
|
||||
const IdentifierInfo *II);
|
||||
|
||||
/// Returns the nested name specifier representing the global
|
||||
/// scope.
|
||||
static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context);
|
||||
|
||||
/// Returns the nested name specifier representing the __super scope
|
||||
/// for the given CXXRecordDecl.
|
||||
static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context,
|
||||
CXXRecordDecl *RD);
|
||||
|
||||
/// Return the prefix of this nested name specifier.
|
||||
///
|
||||
/// The prefix contains all of the parts of the nested name
|
||||
/// specifier that precede this current specifier. For example, for a
|
||||
/// nested name specifier that represents "foo::bar::", the current
|
||||
/// specifier will contain "bar::" and the prefix will contain
|
||||
/// "foo::".
|
||||
NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); }
|
||||
|
||||
/// Determine what kind of nested name specifier is stored.
|
||||
SpecifierKind getKind() const;
|
||||
|
||||
/// Retrieve the identifier stored in this nested name
|
||||
/// specifier.
|
||||
IdentifierInfo *getAsIdentifier() const {
|
||||
if (Prefix.getInt() == StoredIdentifier)
|
||||
return (IdentifierInfo *)Specifier;
|
||||
/// Builds a nested name specifier that names a class through microsoft's
|
||||
/// __super specifier.
|
||||
NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD)
|
||||
: NestedNameSpecifier({StoredKind::NamespaceOrSuper, RD}) {
|
||||
assert(getKind() == Kind::MicrosoftSuper);
|
||||
}
|
||||
|
||||
CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const {
|
||||
switch (getKind()) {
|
||||
case Kind::MicrosoftSuper:
|
||||
return getAsMicrosoftSuper();
|
||||
case Kind::Type:
|
||||
return getAsType()->getAsCXXRecordDecl();
|
||||
case Kind::Global:
|
||||
case Kind::Namespace:
|
||||
case Kind::Null:
|
||||
return nullptr;
|
||||
}
|
||||
llvm_unreachable("Invalid NNS Kind!");
|
||||
}
|
||||
|
||||
/// Retrieve the namespace or namespace alias stored in this nested name
|
||||
/// specifier.
|
||||
NamespaceBaseDecl *getAsNamespace() const;
|
||||
NestedNameSpecifier NestedNameSpecifier::getCanonical() const {
|
||||
switch (getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
// These are canonical and unique.
|
||||
return *this;
|
||||
case NestedNameSpecifier::Kind::Namespace: {
|
||||
// A namespace is canonical; build a nested-name-specifier with
|
||||
// this namespace and no prefix.
|
||||
const NamespaceBaseDecl *ND = getAsNamespaceAndPrefix().Namespace;
|
||||
return NestedNameSpecifier(
|
||||
{StoredKind::NamespaceOrSuper, ND->getNamespace()->getCanonicalDecl()});
|
||||
}
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
return NestedNameSpecifier(
|
||||
getAsType()->getCanonicalTypeInternal().getTypePtr());
|
||||
}
|
||||
llvm_unreachable("unhandled kind");
|
||||
}
|
||||
|
||||
/// Retrieve the record declaration stored in this nested name
|
||||
/// specifier.
|
||||
CXXRecordDecl *getAsRecordDecl() const;
|
||||
bool NestedNameSpecifier::isCanonical() const {
|
||||
return *this == getCanonical();
|
||||
}
|
||||
|
||||
/// Retrieve the type stored in this nested name specifier.
|
||||
const Type *getAsType() const {
|
||||
if (Prefix.getInt() == StoredTypeSpec)
|
||||
return (const Type *)Specifier;
|
||||
TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const {
|
||||
return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/0));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const {
|
||||
if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type)
|
||||
return TypeLoc();
|
||||
return castAsTypeLoc();
|
||||
}
|
||||
|
||||
unsigned
|
||||
NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier Qualifier) {
|
||||
// Location of the trailing '::'.
|
||||
unsigned Length = sizeof(SourceLocation::UIntTy);
|
||||
|
||||
switch (Qualifier.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
// Nothing more to add.
|
||||
break;
|
||||
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
// The location of the identifier or namespace name.
|
||||
Length += sizeof(SourceLocation::UIntTy);
|
||||
break;
|
||||
|
||||
case NestedNameSpecifier::Kind::Type:
|
||||
// The "void*" that points at the TypeLoc data.
|
||||
// Note: the 'template' keyword is part of the TypeLoc.
|
||||
Length += sizeof(void *);
|
||||
break;
|
||||
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
llvm_unreachable("Expected a non-NULL qualifier");
|
||||
}
|
||||
|
||||
/// Fully translate this nested name specifier to a type.
|
||||
/// Unlike getAsType, this will convert this entire nested
|
||||
/// name specifier chain into its equivalent type.
|
||||
const Type *translateToType(const ASTContext &Context) const;
|
||||
return Length;
|
||||
}
|
||||
|
||||
NestedNameSpecifierDependence getDependence() const;
|
||||
NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const {
|
||||
auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix();
|
||||
return {Namespace, NestedNameSpecifierLoc(Prefix, Data)};
|
||||
}
|
||||
|
||||
/// Whether this nested name specifier refers to a dependent
|
||||
/// type or not.
|
||||
bool isDependent() const;
|
||||
NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const {
|
||||
if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace)
|
||||
return {};
|
||||
return castAsNamespaceAndPrefix();
|
||||
}
|
||||
|
||||
/// Whether this nested name specifier involves a template
|
||||
/// parameter.
|
||||
bool isInstantiationDependent() const;
|
||||
unsigned NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier Qualifier) {
|
||||
unsigned Length = 0;
|
||||
for (; Qualifier; Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) {
|
||||
Length += getLocalDataLength(Qualifier);
|
||||
if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace)
|
||||
break;
|
||||
}
|
||||
return Length;
|
||||
}
|
||||
|
||||
/// Whether this nested-name-specifier contains an unexpanded
|
||||
/// parameter pack (for C++11 variadic templates).
|
||||
bool containsUnexpandedParameterPack() const;
|
||||
unsigned NestedNameSpecifierLoc::getDataLength() const {
|
||||
return getDataLength(Qualifier);
|
||||
}
|
||||
|
||||
/// Whether this nested name specifier contains an error.
|
||||
bool containsErrors() const;
|
||||
|
||||
/// Print this nested name specifier to the given output stream. If
|
||||
/// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
|
||||
/// `ns::SomeTemplate<int, MyClass>` instead of
|
||||
/// `ns::SomeTemplate<Container::value_type, T>`.
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool ResolveTemplateArguments = false,
|
||||
bool PrintFinalScopeResOp = true) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddPointer(Prefix.getOpaqueValue());
|
||||
ID.AddPointer(Specifier);
|
||||
SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
|
||||
switch (auto Kind = Qualifier.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
return SourceRange();
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
return LoadSourceLocation(/*Offset=*/0);
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper: {
|
||||
unsigned Offset =
|
||||
Kind == NestedNameSpecifier::Kind::Namespace
|
||||
? getDataLength(Qualifier.getAsNamespaceAndPrefix().Prefix)
|
||||
: 0;
|
||||
return SourceRange(
|
||||
LoadSourceLocation(Offset),
|
||||
LoadSourceLocation(Offset + sizeof(SourceLocation::UIntTy)));
|
||||
}
|
||||
case NestedNameSpecifier::Kind::Type: {
|
||||
// The "void*" that points at the TypeLoc data.
|
||||
// Note: the 'template' keyword is part of the TypeLoc.
|
||||
void *TypeData = LoadPointer(/*Offset=*/0);
|
||||
TypeLoc TL(Qualifier.getAsType(), TypeData);
|
||||
return SourceRange(TL.getBeginLoc(), LoadSourceLocation(sizeof(void *)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Dump the nested name specifier to standard output to aid
|
||||
/// in debugging.
|
||||
void dump(const LangOptions &LO) const;
|
||||
void dump() const;
|
||||
void dump(llvm::raw_ostream &OS) const;
|
||||
void dump(llvm::raw_ostream &OS, const LangOptions &LO) const;
|
||||
};
|
||||
llvm_unreachable("Invalid NNS Kind!");
|
||||
}
|
||||
|
||||
/// A C++ nested-name-specifier augmented with source location
|
||||
/// information.
|
||||
class NestedNameSpecifierLoc {
|
||||
NestedNameSpecifier *Qualifier = nullptr;
|
||||
void *Data = nullptr;
|
||||
SourceRange NestedNameSpecifierLoc::getSourceRange() const {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
/// Determines the data length for the last component in the
|
||||
/// given nested-name-specifier.
|
||||
static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier);
|
||||
SourceLocation NestedNameSpecifierLoc::getEndLoc() const {
|
||||
return getLocalSourceRange().getEnd();
|
||||
}
|
||||
|
||||
/// Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
static unsigned getDataLength(NestedNameSpecifier *Qualifier);
|
||||
/// Retrieve the location of the beginning of this
|
||||
/// component of the nested-name-specifier.
|
||||
SourceLocation NestedNameSpecifierLoc::getLocalBeginLoc() const {
|
||||
return getLocalSourceRange().getBegin();
|
||||
}
|
||||
|
||||
public:
|
||||
/// Construct an empty nested-name-specifier.
|
||||
NestedNameSpecifierLoc() = default;
|
||||
|
||||
/// Construct a nested-name-specifier with source location information
|
||||
/// from
|
||||
NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data)
|
||||
: Qualifier(Qualifier), Data(Data) {}
|
||||
|
||||
/// Evaluates true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
explicit operator bool() const { return Qualifier; }
|
||||
|
||||
/// Evaluates true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
bool hasQualifier() const { return Qualifier; }
|
||||
|
||||
/// Retrieve the nested-name-specifier to which this instance
|
||||
/// refers.
|
||||
NestedNameSpecifier *getNestedNameSpecifier() const {
|
||||
return Qualifier;
|
||||
}
|
||||
|
||||
/// Retrieve the opaque pointer that refers to source-location data.
|
||||
void *getOpaqueData() const { return Data; }
|
||||
|
||||
/// Retrieve the source range covering the entirety of this
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c \::std::vector<int>::, the returned source range would cover
|
||||
/// from the initial '::' to the last '::'.
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
}
|
||||
|
||||
/// Retrieve the source range covering just the last part of
|
||||
/// this nested-name-specifier, not including the prefix.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c \::std::vector<int>::, the returned source range would cover
|
||||
/// from "vector" to the last '::'.
|
||||
SourceRange getLocalSourceRange() const;
|
||||
|
||||
/// Retrieve the location of the beginning of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getBeginLoc() const {
|
||||
if (!Qualifier)
|
||||
return SourceLocation();
|
||||
|
||||
NestedNameSpecifierLoc First = *this;
|
||||
while (NestedNameSpecifierLoc Prefix = First.getPrefix())
|
||||
First = Prefix;
|
||||
return First.getLocalSourceRange().getBegin();
|
||||
}
|
||||
|
||||
/// Retrieve the location of the end of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getEndLoc() const { return getLocalSourceRange().getEnd(); }
|
||||
|
||||
/// Retrieve the location of the beginning of this
|
||||
/// component of the nested-name-specifier.
|
||||
SourceLocation getLocalBeginLoc() const {
|
||||
return getLocalSourceRange().getBegin();
|
||||
}
|
||||
|
||||
/// Retrieve the location of the end of this component of the
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getLocalEndLoc() const {
|
||||
return getLocalSourceRange().getEnd();
|
||||
}
|
||||
|
||||
/// Return the prefix of this nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c \::std::vector<int>::, the prefix is \c \::std::. Note that the
|
||||
/// returned prefix may be empty, if this is the first component of
|
||||
/// the nested-name-specifier.
|
||||
NestedNameSpecifierLoc getPrefix() const {
|
||||
if (!Qualifier)
|
||||
return *this;
|
||||
|
||||
return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data);
|
||||
}
|
||||
|
||||
/// For a nested-name-specifier that refers to a type,
|
||||
/// retrieve the type with source-location information.
|
||||
TypeLoc getTypeLoc() const;
|
||||
|
||||
/// Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
unsigned getDataLength() const { return getDataLength(Qualifier); }
|
||||
|
||||
friend bool operator==(NestedNameSpecifierLoc X,
|
||||
NestedNameSpecifierLoc Y) {
|
||||
return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
|
||||
}
|
||||
|
||||
friend bool operator!=(NestedNameSpecifierLoc X,
|
||||
NestedNameSpecifierLoc Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
};
|
||||
|
||||
/// Class that aids in the construction of nested-name-specifiers along
|
||||
/// with source-location information for all of the components of the
|
||||
/// Retrieve the location of the end of this component of the
|
||||
/// nested-name-specifier.
|
||||
class NestedNameSpecifierLocBuilder {
|
||||
/// The current representation of the nested-name-specifier we're
|
||||
/// building.
|
||||
NestedNameSpecifier *Representation = nullptr;
|
||||
SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const {
|
||||
return getLocalSourceRange().getEnd();
|
||||
}
|
||||
|
||||
/// Buffer used to store source-location information for the
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// Note that we explicitly manage the buffer (rather than using a
|
||||
/// SmallVector) because \c Declarator expects it to be possible to memcpy()
|
||||
/// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
|
||||
char *Buffer = nullptr;
|
||||
|
||||
/// The size of the buffer used to store source-location information
|
||||
/// for the nested-name-specifier.
|
||||
unsigned BufferSize = 0;
|
||||
|
||||
/// The capacity of the buffer used to store source-location
|
||||
/// information for the nested-name-specifier.
|
||||
unsigned BufferCapacity = 0;
|
||||
|
||||
public:
|
||||
NestedNameSpecifierLocBuilder() = default;
|
||||
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
NestedNameSpecifierLocBuilder &
|
||||
operator=(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
~NestedNameSpecifierLocBuilder() {
|
||||
if (BufferCapacity)
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
/// Retrieve the representation of the nested-name-specifier.
|
||||
NestedNameSpecifier *getRepresentation() const { return Representation; }
|
||||
|
||||
/// Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'type::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param TL The TypeLoc that describes the type preceding the '::'.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'identifier::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param Identifier The identifier.
|
||||
///
|
||||
/// \param IdentifierLoc The location of the identifier.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, IdentifierInfo *Identifier,
|
||||
SourceLocation IdentifierLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'namespace::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param Namespace The namespace or namespace alias.
|
||||
///
|
||||
/// \param NamespaceLoc The location of the namespace name or the namespace
|
||||
// alias.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, NamespaceBaseDecl *Namespace,
|
||||
SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Turn this (empty) nested-name-specifier into the global
|
||||
/// nested-name-specifier '::'.
|
||||
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Turns this (empty) nested-name-specifier into '__super'
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param RD The declaration of the class in which nested-name-specifier
|
||||
/// appeared.
|
||||
///
|
||||
/// \param SuperLoc The location of the '__super' keyword.
|
||||
/// name.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void MakeSuper(ASTContext &Context, CXXRecordDecl *RD,
|
||||
SourceLocation SuperLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Make a new nested-name-specifier from incomplete source-location
|
||||
/// information.
|
||||
///
|
||||
/// This routine should be used very, very rarely, in cases where we
|
||||
/// need to synthesize a nested-name-specifier. Most code should instead use
|
||||
/// \c Adopt() with a proper \c NestedNameSpecifierLoc.
|
||||
void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier,
|
||||
SourceRange R);
|
||||
|
||||
/// Adopt an existing nested-name-specifier (with source-range
|
||||
/// information).
|
||||
void Adopt(NestedNameSpecifierLoc Other);
|
||||
|
||||
/// Retrieve the source range covered by this nested-name-specifier.
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
|
||||
}
|
||||
|
||||
/// Retrieve a nested-name-specifier with location information,
|
||||
/// copied into the given AST context.
|
||||
///
|
||||
/// \param Context The context into which this nested-name-specifier will be
|
||||
/// copied.
|
||||
NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
|
||||
|
||||
/// Retrieve a nested-name-specifier with location
|
||||
/// information based on the information in this builder.
|
||||
///
|
||||
/// This loc will contain references to the builder's internal data and may
|
||||
/// be invalidated by any change to the builder.
|
||||
NestedNameSpecifierLoc getTemporary() const {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer);
|
||||
}
|
||||
|
||||
/// Clear out this builder, and prepare it to build another
|
||||
/// nested-name-specifier with source-location information.
|
||||
void Clear() {
|
||||
Representation = nullptr;
|
||||
BufferSize = 0;
|
||||
}
|
||||
|
||||
/// Retrieve the underlying buffer.
|
||||
///
|
||||
/// \returns A pair containing a pointer to the buffer of source-location
|
||||
/// data and the size of the source-location data that resides in that
|
||||
/// buffer.
|
||||
std::pair<char *, unsigned> getBuffer() const {
|
||||
return std::make_pair(Buffer, BufferSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending
|
||||
/// NestedNameSpecifiers into a diagnostic with <<.
|
||||
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
|
||||
NestedNameSpecifier *NNS) {
|
||||
DB.AddTaggedVal(reinterpret_cast<uint64_t>(NNS),
|
||||
DiagnosticsEngine::ak_nestednamespec);
|
||||
return DB;
|
||||
SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
|
||||
}
|
||||
|
||||
} // namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <> struct DenseMapInfo<clang::NestedNameSpecifier> {
|
||||
static clang::NestedNameSpecifier getEmptyKey() { return std::nullopt; }
|
||||
|
||||
static clang::NestedNameSpecifier getTombstoneKey() {
|
||||
return clang::NestedNameSpecifier::getInvalid();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const clang::NestedNameSpecifier &V) {
|
||||
return hash_combine(V.getAsVoidPointer());
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<clang::NestedNameSpecifierLoc> {
|
||||
using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier *>;
|
||||
using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier>;
|
||||
using SecondInfo = DenseMapInfo<void *>;
|
||||
|
||||
static clang::NestedNameSpecifierLoc getEmptyKey() {
|
||||
|
586
clang/include/clang/AST/NestedNameSpecifierBase.h
Normal file
586
clang/include/clang/AST/NestedNameSpecifierBase.h
Normal file
@ -0,0 +1,586 @@
|
||||
//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- C++ -*-===//
|
||||
//
|
||||
// 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 defines the NestedNameSpecifier class, which represents
|
||||
// a C++ nested-name-specifier.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H
|
||||
#define LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H
|
||||
|
||||
#include "clang/AST/DependenceFlags.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class ASTContext;
|
||||
class CXXRecordDecl;
|
||||
class NamedDecl;
|
||||
class IdentifierInfo;
|
||||
class LangOptions;
|
||||
class NamespaceBaseDecl;
|
||||
struct PrintingPolicy;
|
||||
class Type;
|
||||
class TypeLoc;
|
||||
|
||||
struct NamespaceAndPrefix;
|
||||
struct alignas(8) NamespaceAndPrefixStorage;
|
||||
|
||||
/// Represents a C++ nested name specifier, such as
|
||||
/// "\::std::vector<int>::".
|
||||
///
|
||||
/// C++ nested name specifiers are the prefixes to qualified
|
||||
/// names. For example, "foo::" in "foo::x" is a nested name
|
||||
/// specifier. Nested name specifiers are made up of a sequence of
|
||||
/// specifiers, each of which can be a namespace, type, decltype specifier, or
|
||||
/// the global specifier ('::'). The last two specifiers can only appear at the
|
||||
/// start of a nested-namespace-specifier.
|
||||
class NestedNameSpecifier {
|
||||
enum class FlagKind { Null, Global, Invalid };
|
||||
enum class StoredKind {
|
||||
Type,
|
||||
NamespaceOrSuper,
|
||||
NamespaceWithGlobal,
|
||||
NamespaceWithNamespace
|
||||
};
|
||||
static constexpr uintptr_t FlagBits = 2, FlagMask = (1u << FlagBits) - 1u,
|
||||
FlagOffset = 1, PtrOffset = FlagBits + FlagOffset,
|
||||
PtrMask = (1u << PtrOffset) - 1u;
|
||||
|
||||
uintptr_t StoredOrFlag;
|
||||
|
||||
explicit NestedNameSpecifier(uintptr_t StoredOrFlag)
|
||||
: StoredOrFlag(StoredOrFlag) {}
|
||||
struct PtrKind {
|
||||
StoredKind SK;
|
||||
const void *Ptr;
|
||||
};
|
||||
explicit NestedNameSpecifier(PtrKind PK)
|
||||
: StoredOrFlag(uintptr_t(PK.Ptr) | (uintptr_t(PK.SK) << FlagOffset)) {
|
||||
assert(PK.Ptr != nullptr);
|
||||
assert((uintptr_t(PK.Ptr) & ((1u << PtrOffset) - 1u)) == 0);
|
||||
assert((uintptr_t(PK.Ptr) >> PtrOffset) != 0);
|
||||
}
|
||||
|
||||
explicit constexpr NestedNameSpecifier(FlagKind K)
|
||||
: StoredOrFlag(uintptr_t(K) << FlagOffset) {}
|
||||
|
||||
bool isStoredKind() const { return (StoredOrFlag >> PtrOffset) != 0; }
|
||||
|
||||
std::pair<StoredKind, const void *> getStored() const {
|
||||
assert(isStoredKind());
|
||||
return {StoredKind(StoredOrFlag >> FlagOffset & FlagMask),
|
||||
reinterpret_cast<const void *>(StoredOrFlag & ~PtrMask)};
|
||||
}
|
||||
|
||||
FlagKind getFlagKind() const {
|
||||
assert(!isStoredKind());
|
||||
return FlagKind(StoredOrFlag >> FlagOffset);
|
||||
}
|
||||
|
||||
static const NamespaceAndPrefixStorage *
|
||||
MakeNamespaceAndPrefixStorage(const ASTContext &Ctx,
|
||||
const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix);
|
||||
static inline PtrKind MakeNamespacePtrKind(const ASTContext &Ctx,
|
||||
const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix);
|
||||
|
||||
public:
|
||||
static constexpr NestedNameSpecifier getInvalid() {
|
||||
return NestedNameSpecifier(FlagKind::Invalid);
|
||||
}
|
||||
|
||||
static constexpr NestedNameSpecifier getGlobal() {
|
||||
return NestedNameSpecifier(FlagKind::Global);
|
||||
}
|
||||
|
||||
NestedNameSpecifier() : NestedNameSpecifier(FlagKind::Invalid) {}
|
||||
|
||||
/// The kind of specifier that completes this nested name
|
||||
/// specifier.
|
||||
enum class Kind {
|
||||
/// Empty.
|
||||
Null,
|
||||
|
||||
/// The global specifier '::'. There is no stored value.
|
||||
Global,
|
||||
|
||||
/// A type, stored as a Type*.
|
||||
Type,
|
||||
|
||||
/// A namespace-like entity, stored as a NamespaceBaseDecl*.
|
||||
Namespace,
|
||||
|
||||
/// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of
|
||||
/// the class it appeared in.
|
||||
MicrosoftSuper,
|
||||
};
|
||||
|
||||
inline Kind getKind() const;
|
||||
|
||||
NestedNameSpecifier(std::nullopt_t) : StoredOrFlag(0) {}
|
||||
|
||||
explicit inline NestedNameSpecifier(const Type *T);
|
||||
|
||||
/// Builds a nested name specifier that names a namespace.
|
||||
inline NestedNameSpecifier(const ASTContext &Ctx,
|
||||
const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix);
|
||||
|
||||
/// Builds a nested name specifier that names a class through microsoft's
|
||||
/// __super specifier.
|
||||
explicit inline NestedNameSpecifier(CXXRecordDecl *RD);
|
||||
|
||||
explicit operator bool() const { return StoredOrFlag != 0; }
|
||||
|
||||
void *getAsVoidPointer() const {
|
||||
return reinterpret_cast<void *>(StoredOrFlag);
|
||||
}
|
||||
static NestedNameSpecifier getFromVoidPointer(const void *Ptr) {
|
||||
return NestedNameSpecifier(reinterpret_cast<uintptr_t>(Ptr));
|
||||
}
|
||||
|
||||
const Type *getAsType() const {
|
||||
auto [Kind, Ptr] = getStored();
|
||||
assert(Kind == StoredKind::Type);
|
||||
assert(Ptr != nullptr);
|
||||
return static_cast<const Type *>(Ptr);
|
||||
}
|
||||
|
||||
inline NamespaceAndPrefix getAsNamespaceAndPrefix() const;
|
||||
|
||||
CXXRecordDecl *getAsMicrosoftSuper() const {
|
||||
auto [Kind, Ptr] = getStored();
|
||||
assert(Kind == StoredKind::NamespaceOrSuper);
|
||||
assert(Ptr != nullptr);
|
||||
return static_cast<CXXRecordDecl *>(const_cast<void *>(Ptr));
|
||||
}
|
||||
|
||||
/// Retrieve the record declaration stored in this nested name
|
||||
/// specifier, or null.
|
||||
inline CXXRecordDecl *getAsRecordDecl() const;
|
||||
|
||||
friend bool operator==(NestedNameSpecifier LHS, NestedNameSpecifier RHS) {
|
||||
return LHS.StoredOrFlag == RHS.StoredOrFlag;
|
||||
}
|
||||
friend bool operator!=(NestedNameSpecifier LHS, NestedNameSpecifier RHS) {
|
||||
return LHS.StoredOrFlag != RHS.StoredOrFlag;
|
||||
}
|
||||
|
||||
/// Retrieves the "canonical" nested name specifier for a
|
||||
/// given nested name specifier.
|
||||
///
|
||||
/// The canonical nested name specifier is a nested name specifier
|
||||
/// that uniquely identifies a type or namespace within the type
|
||||
/// system. For example, given:
|
||||
///
|
||||
/// \code
|
||||
/// namespace N {
|
||||
/// struct S {
|
||||
/// template<typename T> struct X { typename T* type; };
|
||||
/// };
|
||||
/// }
|
||||
///
|
||||
/// template<typename T> struct Y {
|
||||
/// typename N::S::X<T>::type member;
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// Here, the nested-name-specifier for N::S::X<T>:: will be
|
||||
/// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined
|
||||
/// by declarations in the type system and the canonical type for
|
||||
/// the template type parameter 'T' is template-param-0-0.
|
||||
inline NestedNameSpecifier getCanonical() const;
|
||||
|
||||
/// Whether this nested name specifier is canonical.
|
||||
inline bool isCanonical() const;
|
||||
|
||||
/// Whether this nested name specifier starts with a '::'.
|
||||
bool isFullyQualified() const;
|
||||
|
||||
NestedNameSpecifierDependence getDependence() const;
|
||||
|
||||
/// Whether this nested name specifier refers to a dependent
|
||||
/// type or not.
|
||||
bool isDependent() const {
|
||||
return getDependence() & NestedNameSpecifierDependence::Dependent;
|
||||
}
|
||||
|
||||
/// Whether this nested name specifier involves a template
|
||||
/// parameter.
|
||||
bool isInstantiationDependent() const {
|
||||
return getDependence() & NestedNameSpecifierDependence::Instantiation;
|
||||
}
|
||||
|
||||
/// Whether this nested-name-specifier contains an unexpanded
|
||||
/// parameter pack (for C++11 variadic templates).
|
||||
bool containsUnexpandedParameterPack() const {
|
||||
return getDependence() & NestedNameSpecifierDependence::UnexpandedPack;
|
||||
}
|
||||
|
||||
/// Whether this nested name specifier contains an error.
|
||||
bool containsErrors() const {
|
||||
return getDependence() & NestedNameSpecifierDependence::Error;
|
||||
}
|
||||
|
||||
/// Print this nested name specifier to the given output stream. If
|
||||
/// `ResolveTemplateArguments` is true, we'll print actual types, e.g.
|
||||
/// `ns::SomeTemplate<int, MyClass>` instead of
|
||||
/// `ns::SomeTemplate<Container::value_type, T>`.
|
||||
void print(raw_ostream &OS, const PrintingPolicy &Policy,
|
||||
bool ResolveTemplateArguments = false,
|
||||
bool PrintFinalScopeResOp = true) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddInteger(StoredOrFlag);
|
||||
}
|
||||
|
||||
/// Dump the nested name specifier to aid in debugging.
|
||||
void dump(llvm::raw_ostream *OS = nullptr,
|
||||
const LangOptions *LO = nullptr) const;
|
||||
void dump(const LangOptions &LO) const;
|
||||
void dump(llvm::raw_ostream &OS) const;
|
||||
void dump(llvm::raw_ostream &OS, const LangOptions &LO) const;
|
||||
|
||||
static constexpr auto NumLowBitsAvailable = FlagOffset;
|
||||
};
|
||||
|
||||
struct NamespaceAndPrefix {
|
||||
const NamespaceBaseDecl *Namespace;
|
||||
NestedNameSpecifier Prefix;
|
||||
};
|
||||
|
||||
struct alignas(8) NamespaceAndPrefixStorage : NamespaceAndPrefix,
|
||||
llvm::FoldingSetNode {
|
||||
NamespaceAndPrefixStorage(const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix)
|
||||
: NamespaceAndPrefix{Namespace, Prefix} {}
|
||||
void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Namespace, Prefix); }
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
const NamespaceBaseDecl *Namespace,
|
||||
NestedNameSpecifier Prefix) {
|
||||
ID.AddPointer(Namespace);
|
||||
Prefix.Profile(ID);
|
||||
}
|
||||
};
|
||||
|
||||
NamespaceAndPrefix NestedNameSpecifier::getAsNamespaceAndPrefix() const {
|
||||
auto [Kind, Ptr] = getStored();
|
||||
switch (Kind) {
|
||||
case StoredKind::NamespaceOrSuper:
|
||||
case StoredKind::NamespaceWithGlobal:
|
||||
return {static_cast<const NamespaceBaseDecl *>(Ptr),
|
||||
Kind == StoredKind::NamespaceWithGlobal
|
||||
? NestedNameSpecifier::getGlobal()
|
||||
: std::nullopt};
|
||||
case StoredKind::NamespaceWithNamespace:
|
||||
return *static_cast<const NamespaceAndPrefixStorage *>(Ptr);
|
||||
case StoredKind::Type:;
|
||||
}
|
||||
llvm_unreachable("unexpected stored kind");
|
||||
}
|
||||
|
||||
struct NamespaceAndPrefixLoc;
|
||||
|
||||
/// A C++ nested-name-specifier augmented with source location
|
||||
/// information.
|
||||
class NestedNameSpecifierLoc {
|
||||
NestedNameSpecifier Qualifier = std::nullopt;
|
||||
void *Data = nullptr;
|
||||
|
||||
/// Load a (possibly unaligned) source location from a given address
|
||||
/// and offset.
|
||||
SourceLocation LoadSourceLocation(unsigned Offset) const {
|
||||
SourceLocation::UIntTy Raw;
|
||||
memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(Raw));
|
||||
return SourceLocation::getFromRawEncoding(Raw);
|
||||
}
|
||||
|
||||
/// Load a (possibly unaligned) pointer from a given address and
|
||||
/// offset.
|
||||
void *LoadPointer(unsigned Offset) const {
|
||||
void *Result;
|
||||
memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void *));
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// Determines the data length for the last component in the
|
||||
/// given nested-name-specifier.
|
||||
static inline unsigned getLocalDataLength(NestedNameSpecifier Qualifier);
|
||||
|
||||
/// Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
static inline unsigned getDataLength(NestedNameSpecifier Qualifier);
|
||||
|
||||
public:
|
||||
/// Construct an empty nested-name-specifier.
|
||||
NestedNameSpecifierLoc() = default;
|
||||
|
||||
/// Construct a nested-name-specifier with source location information
|
||||
/// from
|
||||
NestedNameSpecifierLoc(NestedNameSpecifier Qualifier, void *Data)
|
||||
: Qualifier(Qualifier), Data(Data) {}
|
||||
|
||||
/// Evaluates true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
explicit operator bool() const { return bool(Qualifier); }
|
||||
|
||||
/// Evaluates true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
bool hasQualifier() const { return bool(Qualifier); }
|
||||
|
||||
/// Retrieve the nested-name-specifier to which this instance
|
||||
/// refers.
|
||||
NestedNameSpecifier getNestedNameSpecifier() const { return Qualifier; }
|
||||
|
||||
/// Retrieve the opaque pointer that refers to source-location data.
|
||||
void *getOpaqueData() const { return Data; }
|
||||
|
||||
/// Retrieve the source range covering the entirety of this
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c \::std::vector<int>::, the returned source range would cover
|
||||
/// from the initial '::' to the last '::'.
|
||||
inline SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
/// Retrieve the source range covering just the last part of
|
||||
/// this nested-name-specifier, not including the prefix.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c \::std::vector<int>::, the returned source range would cover
|
||||
/// from "vector" to the last '::'.
|
||||
inline SourceRange getLocalSourceRange() const;
|
||||
|
||||
/// Retrieve the location of the beginning of this
|
||||
/// nested-name-specifier.
|
||||
SourceLocation getBeginLoc() const;
|
||||
|
||||
/// Retrieve the location of the end of this
|
||||
/// nested-name-specifier.
|
||||
inline SourceLocation getEndLoc() const;
|
||||
|
||||
/// Retrieve the location of the beginning of this
|
||||
/// component of the nested-name-specifier.
|
||||
inline SourceLocation getLocalBeginLoc() const;
|
||||
|
||||
/// Retrieve the location of the end of this component of the
|
||||
/// nested-name-specifier.
|
||||
inline SourceLocation getLocalEndLoc() const;
|
||||
|
||||
/// For a nested-name-specifier that refers to a namespace,
|
||||
/// retrieve the namespace and its prefix.
|
||||
///
|
||||
/// For example, if this instance refers to a nested-name-specifier
|
||||
/// \c \::std::chrono::, the prefix is \c \::std::. Note that the
|
||||
/// returned prefix may be empty, if this is the first component of
|
||||
/// the nested-name-specifier.
|
||||
inline NamespaceAndPrefixLoc castAsNamespaceAndPrefix() const;
|
||||
inline NamespaceAndPrefixLoc getAsNamespaceAndPrefix() const;
|
||||
|
||||
/// For a nested-name-specifier that refers to a type,
|
||||
/// retrieve the type with source-location information.
|
||||
inline TypeLoc castAsTypeLoc() const;
|
||||
inline TypeLoc getAsTypeLoc() const;
|
||||
|
||||
/// Determines the data length for the entire
|
||||
/// nested-name-specifier.
|
||||
inline unsigned getDataLength() const;
|
||||
|
||||
friend bool operator==(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) {
|
||||
return X.Qualifier == Y.Qualifier && X.Data == Y.Data;
|
||||
}
|
||||
|
||||
friend bool operator!=(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) {
|
||||
return !(X == Y);
|
||||
}
|
||||
};
|
||||
|
||||
struct NamespaceAndPrefixLoc {
|
||||
const NamespaceBaseDecl *Namespace = nullptr;
|
||||
NestedNameSpecifierLoc Prefix;
|
||||
|
||||
explicit operator bool() const { return Namespace != nullptr; }
|
||||
};
|
||||
|
||||
/// Class that aids in the construction of nested-name-specifiers along
|
||||
/// with source-location information for all of the components of the
|
||||
/// nested-name-specifier.
|
||||
class NestedNameSpecifierLocBuilder {
|
||||
/// The current representation of the nested-name-specifier we're
|
||||
/// building.
|
||||
NestedNameSpecifier Representation = std::nullopt;
|
||||
|
||||
/// Buffer used to store source-location information for the
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// Note that we explicitly manage the buffer (rather than using a
|
||||
/// SmallVector) because \c Declarator expects it to be possible to memcpy()
|
||||
/// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder.
|
||||
char *Buffer = nullptr;
|
||||
|
||||
/// The size of the buffer used to store source-location information
|
||||
/// for the nested-name-specifier.
|
||||
unsigned BufferSize = 0;
|
||||
|
||||
/// The capacity of the buffer used to store source-location
|
||||
/// information for the nested-name-specifier.
|
||||
unsigned BufferCapacity = 0;
|
||||
|
||||
void PushTrivial(ASTContext &Context, NestedNameSpecifier Qualifier,
|
||||
SourceRange R);
|
||||
|
||||
public:
|
||||
NestedNameSpecifierLocBuilder() = default;
|
||||
NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
NestedNameSpecifierLocBuilder &
|
||||
operator=(const NestedNameSpecifierLocBuilder &Other);
|
||||
|
||||
~NestedNameSpecifierLocBuilder() {
|
||||
if (BufferCapacity)
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
/// Retrieve the representation of the nested-name-specifier.
|
||||
NestedNameSpecifier getRepresentation() const { return Representation; }
|
||||
|
||||
/// Make a nested-name-specifier of the form 'type::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param TL The TypeLoc that describes the type preceding the '::'.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Extend the current nested-name-specifier by another
|
||||
/// nested-name-specifier component of the form 'namespace::'.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param Namespace The namespace.
|
||||
///
|
||||
/// \param NamespaceLoc The location of the namespace name.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void Extend(ASTContext &Context, const NamespaceBaseDecl *Namespace,
|
||||
SourceLocation NamespaceLoc, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Turn this (empty) nested-name-specifier into the global
|
||||
/// nested-name-specifier '::'.
|
||||
void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc);
|
||||
|
||||
/// Turns this (empty) nested-name-specifier into '__super'
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
/// \param Context The AST context in which this nested-name-specifier
|
||||
/// resides.
|
||||
///
|
||||
/// \param RD The declaration of the class in which nested-name-specifier
|
||||
/// appeared.
|
||||
///
|
||||
/// \param SuperLoc The location of the '__super' keyword.
|
||||
/// name.
|
||||
///
|
||||
/// \param ColonColonLoc The location of the trailing '::'.
|
||||
void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD,
|
||||
SourceLocation SuperLoc,
|
||||
SourceLocation ColonColonLoc);
|
||||
|
||||
/// Make a new nested-name-specifier from incomplete source-location
|
||||
/// information.
|
||||
///
|
||||
/// This routine should be used very, very rarely, in cases where we
|
||||
/// need to synthesize a nested-name-specifier. Most code should instead use
|
||||
/// \c Adopt() with a proper \c NestedNameSpecifierLoc.
|
||||
void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier,
|
||||
SourceRange R) {
|
||||
Representation = Qualifier;
|
||||
BufferSize = 0;
|
||||
PushTrivial(Context, Qualifier, R);
|
||||
}
|
||||
|
||||
/// Adopt an existing nested-name-specifier (with source-range
|
||||
/// information).
|
||||
void Adopt(NestedNameSpecifierLoc Other);
|
||||
|
||||
/// Retrieve the source range covered by this nested-name-specifier.
|
||||
inline SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
/// Retrieve a nested-name-specifier with location information,
|
||||
/// copied into the given AST context.
|
||||
///
|
||||
/// \param Context The context into which this nested-name-specifier will be
|
||||
/// copied.
|
||||
NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const;
|
||||
|
||||
/// Retrieve a nested-name-specifier with location
|
||||
/// information based on the information in this builder.
|
||||
///
|
||||
/// This loc will contain references to the builder's internal data and may
|
||||
/// be invalidated by any change to the builder.
|
||||
NestedNameSpecifierLoc getTemporary() const {
|
||||
return NestedNameSpecifierLoc(Representation, Buffer);
|
||||
}
|
||||
|
||||
/// Clear out this builder, and prepare it to build another
|
||||
/// nested-name-specifier with source-location information.
|
||||
void Clear() {
|
||||
Representation = std::nullopt;
|
||||
BufferSize = 0;
|
||||
}
|
||||
|
||||
/// Retrieve the underlying buffer.
|
||||
///
|
||||
/// \returns A pair containing a pointer to the buffer of source-location
|
||||
/// data and the size of the source-location data that resides in that
|
||||
/// buffer.
|
||||
std::pair<char *, unsigned> getBuffer() const {
|
||||
return std::make_pair(Buffer, BufferSize);
|
||||
}
|
||||
};
|
||||
|
||||
/// Insertion operator for diagnostics. This allows sending
|
||||
/// NestedNameSpecifiers into a diagnostic with <<.
|
||||
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
|
||||
NestedNameSpecifier NNS) {
|
||||
DB.AddTaggedVal(reinterpret_cast<uintptr_t>(NNS.getAsVoidPointer()),
|
||||
DiagnosticsEngine::ak_nestednamespec);
|
||||
return DB;
|
||||
}
|
||||
|
||||
} // namespace clang
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <> struct PointerLikeTypeTraits<clang::NestedNameSpecifier> {
|
||||
static void *getAsVoidPointer(clang::NestedNameSpecifier P) {
|
||||
return P.getAsVoidPointer();
|
||||
}
|
||||
static clang::NestedNameSpecifier getFromVoidPointer(const void *P) {
|
||||
return clang::NestedNameSpecifier::getFromVoidPointer(P);
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable =
|
||||
clang::NestedNameSpecifier::NumLowBitsAvailable;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H
|
@ -93,7 +93,7 @@ public:
|
||||
void AddQualType(QualType T);
|
||||
void AddStmt(const Stmt *S);
|
||||
void AddIdentifierInfo(const IdentifierInfo *II);
|
||||
void AddNestedNameSpecifier(const NestedNameSpecifier *NNS);
|
||||
void AddNestedNameSpecifier(NestedNameSpecifier NNS);
|
||||
void AddDependentTemplateName(const DependentTemplateStorage &Name);
|
||||
void AddTemplateName(TemplateName Name);
|
||||
void AddDeclarationNameInfo(DeclarationNameInfo NameInfo,
|
||||
|
@ -63,9 +63,9 @@ struct PrintingPolicy {
|
||||
SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
|
||||
SuppressScope(false), SuppressUnwrittenScope(false),
|
||||
SuppressInlineNamespace(SuppressInlineNamespaceMode::Redundant),
|
||||
SuppressElaboration(false), SuppressInitializers(false),
|
||||
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
||||
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
|
||||
SuppressInitializers(false), ConstantArraySizeAsWritten(false),
|
||||
AnonymousTagLocations(true), SuppressStrongLifetime(false),
|
||||
SuppressLifetimeQualifiers(false),
|
||||
SuppressTemplateArgsInCXXConstructors(false),
|
||||
SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
|
||||
Nullptr(LO.CPlusPlus11 || LO.C23), NullptrTypeInNamespace(LO.CPlusPlus),
|
||||
@ -150,11 +150,6 @@ struct PrintingPolicy {
|
||||
LLVM_PREFERRED_TYPE(SuppressInlineNamespaceMode)
|
||||
unsigned SuppressInlineNamespace : 2;
|
||||
|
||||
/// Ignore qualifiers and tag keywords as specified by elaborated type sugar,
|
||||
/// instead letting the underlying type print as normal.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned SuppressElaboration : 1;
|
||||
|
||||
/// Suppress printing of variable initializers.
|
||||
///
|
||||
/// This flag is used when printing the loop variable in a for-range
|
||||
|
@ -127,9 +127,8 @@ def LValuePathSerializationHelper :
|
||||
PropertyType<"APValue::LValuePathSerializationHelper"> {
|
||||
let BufferElementTypes = [ LValuePathEntry ];
|
||||
}
|
||||
def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">;
|
||||
def NestedNameSpecifierKind :
|
||||
EnumPropertyType<"NestedNameSpecifier::SpecifierKind">;
|
||||
def NestedNameSpecifier : PropertyType<"NestedNameSpecifier">;
|
||||
def NestedNameSpecifierKind : EnumPropertyType<"NestedNameSpecifier::Kind">;
|
||||
def OverloadedOperatorKind : EnumPropertyType;
|
||||
def Qualifiers : PropertyType;
|
||||
def QualType : DefaultValuePropertyType;
|
||||
|
@ -87,6 +87,16 @@ std::string getFullyQualifiedName(QualType QT, const ASTContext &Ctx,
|
||||
/// specifier "::" should be prepended or not.
|
||||
QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
|
||||
bool WithGlobalNsPrefix = false);
|
||||
|
||||
/// Get the fully qualified name for the declared context of a declaration.
|
||||
///
|
||||
/// \param[in] Ctx - the ASTContext to be used.
|
||||
/// \param[in] Decl - the declaration for which to get the fully qualified name.
|
||||
/// \param[in] WithGlobalNsPrefix - If true, then the global namespace
|
||||
/// specifier "::" will be prepended to the fully qualified name.
|
||||
NestedNameSpecifier
|
||||
getFullyQualifiedDeclaredContext(const ASTContext &Ctx, const Decl *Decl,
|
||||
bool WithGlobalNsPrefix = false);
|
||||
} // end namespace TypeName
|
||||
} // end namespace clang
|
||||
#endif // LLVM_CLANG_AST_QUALTYPENAMES_H
|
||||
|
@ -216,14 +216,14 @@ public:
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true
|
||||
/// otherwise (including when the argument is a Null type).
|
||||
bool TraverseType(QualType T);
|
||||
bool TraverseType(QualType T, bool TraverseQualifier = true);
|
||||
|
||||
/// Recursively visit a type with location, by dispatching to
|
||||
/// Traverse*TypeLoc() based on the argument type's getTypeClass() property.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true
|
||||
/// otherwise (including when the argument is a Null type location).
|
||||
bool TraverseTypeLoc(TypeLoc TL);
|
||||
bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true);
|
||||
|
||||
/// Recursively visit an attribute, by dispatching to
|
||||
/// Traverse*Attr() based on the argument's dynamic type.
|
||||
@ -242,7 +242,7 @@ public:
|
||||
/// Recursively visit a C++ nested-name-specifier.
|
||||
///
|
||||
/// \returns false if the visitation was terminated early, true otherwise.
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
|
||||
bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS);
|
||||
|
||||
/// Recursively visit a C++ nested-name-specifier with location
|
||||
/// information.
|
||||
@ -389,7 +389,8 @@ public:
|
||||
|
||||
// Declare Traverse*() for all concrete Type classes.
|
||||
#define ABSTRACT_TYPE(CLASS, BASE)
|
||||
#define TYPE(CLASS, BASE) bool Traverse##CLASS##Type(CLASS##Type *T);
|
||||
#define TYPE(CLASS, BASE) \
|
||||
bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier);
|
||||
#include "clang/AST/TypeNodes.inc"
|
||||
// The above header #undefs ABSTRACT_TYPE and TYPE upon exit.
|
||||
|
||||
@ -410,7 +411,8 @@ public:
|
||||
|
||||
// Declare Traverse*() for all concrete TypeLoc classes.
|
||||
#define ABSTRACT_TYPELOC(CLASS, BASE)
|
||||
#define TYPELOC(CLASS, BASE) bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL);
|
||||
#define TYPELOC(CLASS, BASE) \
|
||||
bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier);
|
||||
#include "clang/AST/TypeLocNodes.def"
|
||||
// The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit.
|
||||
|
||||
@ -499,6 +501,8 @@ private:
|
||||
bool TraverseOMPExecutableDirective(OMPExecutableDirective *S);
|
||||
bool TraverseOMPLoopDirective(OMPLoopDirective *S);
|
||||
bool TraverseOMPClause(OMPClause *C);
|
||||
bool TraverseTagType(TagType *T, bool TraverseQualifier);
|
||||
bool TraverseTagTypeLoc(TagTypeLoc TL, bool TraverseQualifier);
|
||||
#define GEN_CLANG_CLAUSE_CLASS
|
||||
#define CLAUSE_CLASS(Enum, Str, Class) bool Visit##Class(Class *C);
|
||||
#include "llvm/Frontend/OpenMP/OMP.inc"
|
||||
@ -698,7 +702,8 @@ RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S, DataRecursionQueue *Queue) {
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
|
||||
bool RecursiveASTVisitor<Derived>::TraverseType(QualType T,
|
||||
bool TraverseQualifier) {
|
||||
if (T.isNull())
|
||||
return true;
|
||||
|
||||
@ -707,7 +712,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
|
||||
#define TYPE(CLASS, BASE) \
|
||||
case Type::CLASS: \
|
||||
return getDerived().Traverse##CLASS##Type( \
|
||||
static_cast<CLASS##Type *>(const_cast<Type *>(T.getTypePtr())));
|
||||
static_cast<CLASS##Type *>(const_cast<Type *>(T.getTypePtr())), \
|
||||
TraverseQualifier);
|
||||
#include "clang/AST/TypeNodes.inc"
|
||||
}
|
||||
|
||||
@ -715,7 +721,8 @@ bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) {
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL,
|
||||
bool TraverseQualifier) {
|
||||
if (TL.isNull())
|
||||
return true;
|
||||
|
||||
@ -723,7 +730,8 @@ bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
|
||||
#define ABSTRACT_TYPELOC(CLASS, BASE)
|
||||
#define TYPELOC(CLASS, BASE) \
|
||||
case TypeLoc::CLASS: \
|
||||
return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>());
|
||||
return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>(), \
|
||||
TraverseQualifier);
|
||||
#include "clang/AST/TypeLocNodes.def"
|
||||
}
|
||||
|
||||
@ -779,46 +787,43 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier(
|
||||
NestedNameSpecifier *NNS) {
|
||||
if (!NNS)
|
||||
NestedNameSpecifier NNS) {
|
||||
switch (NNS.getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
return true;
|
||||
|
||||
if (NNS->getPrefix())
|
||||
TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix()));
|
||||
|
||||
switch (NNS->getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Super:
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
TRY_TO(TraverseNestedNameSpecifier(NNS.getAsNamespaceAndPrefix().Prefix));
|
||||
return true;
|
||||
case NestedNameSpecifier::Kind::Type: {
|
||||
auto *T = const_cast<Type *>(NNS.getAsType());
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getPrefix()));
|
||||
TRY_TO(TraverseType(QualType(T, 0), /*TraverseQualifier=*/false));
|
||||
return true;
|
||||
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
TRY_TO(TraverseType(QualType(NNS->getAsType(), 0)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
llvm_unreachable("unhandled kind");
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc(
|
||||
NestedNameSpecifierLoc NNS) {
|
||||
if (!NNS)
|
||||
switch (NNS.getNestedNameSpecifier().getKind()) {
|
||||
case NestedNameSpecifier::Kind::Null:
|
||||
case NestedNameSpecifier::Kind::Global:
|
||||
case NestedNameSpecifier::Kind::MicrosoftSuper:
|
||||
return true;
|
||||
|
||||
if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(Prefix));
|
||||
|
||||
switch (NNS.getNestedNameSpecifier()->getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
case NestedNameSpecifier::Namespace:
|
||||
case NestedNameSpecifier::Global:
|
||||
case NestedNameSpecifier::Super:
|
||||
case NestedNameSpecifier::Kind::Namespace:
|
||||
TRY_TO(
|
||||
TraverseNestedNameSpecifierLoc(NNS.castAsNamespaceAndPrefix().Prefix));
|
||||
return true;
|
||||
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
TRY_TO(TraverseTypeLoc(NNS.getTypeLoc()));
|
||||
break;
|
||||
case NestedNameSpecifier::Kind::Type: {
|
||||
TypeLoc TL = NNS.castAsTypeLoc();
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getPrefix()));
|
||||
TRY_TO(TraverseTypeLoc(TL, /*TraverseQualifier=*/false));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -975,10 +980,13 @@ RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr *LE,
|
||||
// This macro makes available a variable T, the passed-in type.
|
||||
#define DEF_TRAVERSE_TYPE(TYPE, CODE) \
|
||||
template <typename Derived> \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T) { \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##TYPE(TYPE *T, \
|
||||
bool TraverseQualifier) { \
|
||||
if (!getDerived().shouldTraversePostOrder()) \
|
||||
TRY_TO(WalkUpFrom##TYPE(T)); \
|
||||
{ CODE; } \
|
||||
{ \
|
||||
CODE; \
|
||||
} \
|
||||
if (getDerived().shouldTraversePostOrder()) \
|
||||
TRY_TO(WalkUpFrom##TYPE(T)); \
|
||||
return true; \
|
||||
@ -1000,10 +1008,11 @@ DEF_TRAVERSE_TYPE(RValueReferenceType,
|
||||
{ TRY_TO(TraverseType(T->getPointeeType())); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(MemberPointerType, {
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
if (T->isSugared())
|
||||
TRY_TO(TraverseType(
|
||||
QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0)));
|
||||
NestedNameSpecifier Qualifier =
|
||||
T->isSugared() ? cast<MemberPointerType>(T->getCanonicalTypeUnqualified())
|
||||
->getQualifier()
|
||||
: T->getQualifier();
|
||||
TRY_TO(TraverseNestedNameSpecifier(Qualifier));
|
||||
TRY_TO(TraverseType(T->getPointeeType()));
|
||||
})
|
||||
|
||||
@ -1087,9 +1096,18 @@ DEF_TRAVERSE_TYPE(FunctionProtoType, {
|
||||
TRY_TO(TraverseStmt(NE));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(UsingType, {})
|
||||
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {})
|
||||
DEF_TRAVERSE_TYPE(TypedefType, {})
|
||||
DEF_TRAVERSE_TYPE(UsingType, {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(UnresolvedUsingType, {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(TypedefType, {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(TypeOfExprType,
|
||||
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
|
||||
@ -1115,13 +1133,7 @@ DEF_TRAVERSE_TYPE(AutoType, {
|
||||
TRY_TO(TraverseTemplateArguments(T->getTypeConstraintArguments()));
|
||||
}
|
||||
})
|
||||
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(RecordType, {})
|
||||
DEF_TRAVERSE_TYPE(EnumType, {})
|
||||
DEF_TRAVERSE_TYPE(TemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, {
|
||||
TRY_TO(TraverseType(T->getReplacementType()));
|
||||
@ -1130,13 +1142,6 @@ DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, {
|
||||
TRY_TO(TraverseTemplateArgument(T->getArgumentPack()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
TRY_TO(TraverseTemplateArguments(T->template_arguments()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(InjectedClassNameType, {})
|
||||
|
||||
DEF_TRAVERSE_TYPE(AttributedType,
|
||||
{ TRY_TO(TraverseType(T->getModifiedType())); })
|
||||
|
||||
@ -1165,22 +1170,54 @@ DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); })
|
||||
DEF_TRAVERSE_TYPE(MacroQualifiedType,
|
||||
{ TRY_TO(TraverseType(T->getUnderlyingType())); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(ElaboratedType, {
|
||||
if (T->getQualifier()) {
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTagType(TagType *T,
|
||||
bool TraverseQualifier) {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
}
|
||||
TRY_TO(TraverseType(T->getNamedType()));
|
||||
})
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_TYPE(DependentNameType,
|
||||
{ TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); })
|
||||
DEF_TRAVERSE_TYPE(EnumType, { TRY_TO(TraverseTagType(T, TraverseQualifier)); })
|
||||
DEF_TRAVERSE_TYPE(RecordType,
|
||||
{ TRY_TO(TraverseTagType(T, TraverseQualifier)); })
|
||||
DEF_TRAVERSE_TYPE(InjectedClassNameType,
|
||||
{ TRY_TO(TraverseTagType(T, TraverseQualifier)); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(DependentNameType, {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, {
|
||||
const DependentTemplateStorage &S = T->getDependentTemplateName();
|
||||
TRY_TO(TraverseNestedNameSpecifier(S.getQualifier()));
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifier(S.getQualifier()));
|
||||
TRY_TO(TraverseTemplateArguments(T->template_arguments()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(TemplateSpecializationType, {
|
||||
if (TraverseQualifier) {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
} else {
|
||||
// FIXME: Try to preserve the rest of the template name.
|
||||
TRY_TO(TraverseTemplateName(TemplateName(
|
||||
T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true))));
|
||||
}
|
||||
TRY_TO(TraverseTemplateArguments(T->template_arguments()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
|
||||
if (TraverseQualifier) {
|
||||
TRY_TO(TraverseTemplateName(T->getTemplateName()));
|
||||
} else {
|
||||
// FIXME: Try to preserve the rest of the template name.
|
||||
TRY_TO(TraverseTemplateName(TemplateName(
|
||||
T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true))));
|
||||
}
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPE(PackExpansionType, { TRY_TO(TraverseType(T->getPattern())); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(ObjCTypeParamType, {})
|
||||
@ -1221,13 +1258,16 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {})
|
||||
// continue to work.
|
||||
#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \
|
||||
template <typename Derived> \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \
|
||||
bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc( \
|
||||
TYPE##Loc TL, bool TraverseQualifier) { \
|
||||
if (!getDerived().shouldTraversePostOrder()) { \
|
||||
TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
|
||||
if (getDerived().shouldWalkTypesOfTypeLocs()) \
|
||||
TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE *>(TL.getTypePtr()))); \
|
||||
} \
|
||||
{ CODE; } \
|
||||
{ \
|
||||
CODE; \
|
||||
} \
|
||||
if (getDerived().shouldTraversePostOrder()) { \
|
||||
TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \
|
||||
if (getDerived().shouldWalkTypesOfTypeLocs()) \
|
||||
@ -1237,8 +1277,10 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {})
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool
|
||||
RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
||||
bool RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc(
|
||||
QualifiedTypeLoc TL, bool TraverseQualifier) {
|
||||
assert(TraverseQualifier &&
|
||||
"Qualifiers should never occur within NestedNameSpecifiers");
|
||||
// Move this over to the 'main' typeloc tree. Note that this is a
|
||||
// move -- we pretend that we were really looking at the unqualified
|
||||
// typeloc all along -- rather than a recursion, so we don't follow
|
||||
@ -1391,9 +1433,21 @@ DEF_TRAVERSE_TYPELOC(FunctionProtoType, {
|
||||
TRY_TO(TraverseStmt(NE));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(UsingType, {})
|
||||
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {})
|
||||
DEF_TRAVERSE_TYPELOC(TypedefType, {})
|
||||
DEF_TRAVERSE_TYPELOC(UsingType, {
|
||||
if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
|
||||
TraverseQualifier && QualifierLoc)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
|
||||
})
|
||||
DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, {
|
||||
if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
|
||||
TraverseQualifier && QualifierLoc)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
|
||||
})
|
||||
DEF_TRAVERSE_TYPELOC(TypedefType, {
|
||||
if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
|
||||
TraverseQualifier && QualifierLoc)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(TypeOfExprType,
|
||||
{ TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); })
|
||||
@ -1423,13 +1477,6 @@ DEF_TRAVERSE_TYPELOC(AutoType, {
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(RecordType, {})
|
||||
DEF_TRAVERSE_TYPELOC(EnumType, {})
|
||||
DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, {})
|
||||
DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, {
|
||||
TRY_TO(TraverseType(TL.getTypePtr()->getReplacementType()));
|
||||
@ -1438,16 +1485,6 @@ DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, {
|
||||
TRY_TO(TraverseTemplateArgument(TL.getTypePtr()->getArgumentPack()));
|
||||
})
|
||||
|
||||
// FIXME: use the loc for the template name?
|
||||
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
|
||||
TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName()));
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
|
||||
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(MacroQualifiedType,
|
||||
@ -1468,27 +1505,63 @@ DEF_TRAVERSE_TYPELOC(HLSLAttributedResourceType,
|
||||
DEF_TRAVERSE_TYPELOC(HLSLInlineSpirvType,
|
||||
{ TRY_TO(TraverseType(TL.getType())); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ElaboratedType, {
|
||||
if (TL.getQualifierLoc()) {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
}
|
||||
TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc()));
|
||||
})
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::TraverseTagTypeLoc(TagTypeLoc TL,
|
||||
bool TraverseQualifier) {
|
||||
if (NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc();
|
||||
TraverseQualifier && QualifierLoc)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(QualifierLoc));
|
||||
return true;
|
||||
}
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(EnumType,
|
||||
{ TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); })
|
||||
DEF_TRAVERSE_TYPELOC(RecordType,
|
||||
{ TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); })
|
||||
DEF_TRAVERSE_TYPELOC(InjectedClassNameType,
|
||||
{ TRY_TO(TraverseTagTypeLoc(TL, TraverseQualifier)); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DependentNameType, {
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, {
|
||||
if (TL.getQualifierLoc()) {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
}
|
||||
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
|
||||
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
|
||||
// FIXME: Try to preserve the rest of the template name.
|
||||
TRY_TO(TraverseTemplateName(
|
||||
TemplateName(TL.getTypePtr()->getTemplateName().getAsTemplateDecl(
|
||||
/*IgnoreDeduced=*/true))));
|
||||
|
||||
for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
|
||||
TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
|
||||
}
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
|
||||
if (TraverseQualifier)
|
||||
TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()));
|
||||
|
||||
const auto *T = TL.getTypePtr();
|
||||
// FIXME: Try to preserve the rest of the template name.
|
||||
TRY_TO(
|
||||
TraverseTemplateName(TemplateName(T->getTemplateName().getAsTemplateDecl(
|
||||
/*IgnoreDeduced=*/true))));
|
||||
|
||||
TRY_TO(TraverseType(T->getDeducedType()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(PackExpansionType,
|
||||
{ TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); })
|
||||
|
||||
@ -1631,8 +1704,9 @@ DEF_TRAVERSE_DECL(FriendDecl, {
|
||||
TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
|
||||
// Traverse any CXXRecordDecl owned by this type, since
|
||||
// it will not be in the parent context:
|
||||
if (auto *ET = D->getFriendType()->getType()->getAs<ElaboratedType>())
|
||||
TRY_TO(TraverseDecl(ET->getOwnedTagDecl()));
|
||||
if (auto *TT = D->getFriendType()->getType()->getAs<TagType>();
|
||||
TT && TT->isTagOwned())
|
||||
TRY_TO(TraverseDecl(TT->getOriginalDecl()));
|
||||
} else {
|
||||
TRY_TO(TraverseDecl(D->getFriendDecl()));
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
#define LLVM_CLANG_AST_TEMPLATEBASE_H
|
||||
|
||||
#include "clang/AST/DependenceFlags.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/NestedNameSpecifierBase.h"
|
||||
#include "clang/AST/TemplateName.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
@ -478,31 +478,25 @@ public:
|
||||
|
||||
/// Location information for a TemplateArgument.
|
||||
struct TemplateArgumentLocInfo {
|
||||
private:
|
||||
struct TemplateTemplateArgLocInfo {
|
||||
// FIXME: We'd like to just use the qualifier in the TemplateName,
|
||||
// but template arguments get canonicalized too quickly.
|
||||
NestedNameSpecifier *Qualifier;
|
||||
void *QualifierLocData;
|
||||
SourceLocation TemplateKwLoc;
|
||||
SourceLocation TemplateNameLoc;
|
||||
SourceLocation EllipsisLoc;
|
||||
};
|
||||
|
||||
llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *>
|
||||
Pointer;
|
||||
|
||||
TemplateTemplateArgLocInfo *getTemplate() const {
|
||||
return cast<TemplateTemplateArgLocInfo *>(Pointer);
|
||||
}
|
||||
|
||||
public:
|
||||
TemplateArgumentLocInfo() {}
|
||||
TemplateArgumentLocInfo(TypeSourceInfo *Declarator) { Pointer = Declarator; }
|
||||
|
||||
TemplateArgumentLocInfo(Expr *E) { Pointer = E; }
|
||||
// Ctx is used for allocation -- this case is unusually large and also rare,
|
||||
// so we store the payload out-of-line.
|
||||
TemplateArgumentLocInfo(ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
|
||||
TemplateArgumentLocInfo(ASTContext &Ctx, SourceLocation TemplateKwLoc,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
@ -512,10 +506,8 @@ public:
|
||||
|
||||
Expr *getAsExpr() const { return cast<Expr *>(Pointer); }
|
||||
|
||||
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
|
||||
const auto *Template = getTemplate();
|
||||
return NestedNameSpecifierLoc(Template->Qualifier,
|
||||
Template->QualifierLocData);
|
||||
SourceLocation getTemplateKwLoc() const {
|
||||
return getTemplate()->TemplateKwLoc;
|
||||
}
|
||||
|
||||
SourceLocation getTemplateNameLoc() const {
|
||||
@ -525,6 +517,10 @@ public:
|
||||
SourceLocation getTemplateEllipsisLoc() const {
|
||||
return getTemplate()->EllipsisLoc;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *>
|
||||
Pointer;
|
||||
};
|
||||
|
||||
/// Location wrapper for a TemplateArgument. TemplateArgument is to
|
||||
@ -558,14 +554,10 @@ public:
|
||||
}
|
||||
|
||||
TemplateArgumentLoc(ASTContext &Ctx, const TemplateArgument &Argument,
|
||||
SourceLocation TemplateKWLoc,
|
||||
NestedNameSpecifierLoc QualifierLoc,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation EllipsisLoc = SourceLocation())
|
||||
: Argument(Argument),
|
||||
LocInfo(Ctx, QualifierLoc, TemplateNameLoc, EllipsisLoc) {
|
||||
assert(Argument.getKind() == TemplateArgument::Template ||
|
||||
Argument.getKind() == TemplateArgument::TemplateExpansion);
|
||||
}
|
||||
SourceLocation EllipsisLoc = SourceLocation());
|
||||
|
||||
/// - Fetches the primary location of the argument.
|
||||
SourceLocation getLocation() const {
|
||||
@ -614,13 +606,15 @@ public:
|
||||
return LocInfo.getAsExpr();
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc getTemplateQualifierLoc() const {
|
||||
SourceLocation getTemplateKWLoc() const {
|
||||
if (Argument.getKind() != TemplateArgument::Template &&
|
||||
Argument.getKind() != TemplateArgument::TemplateExpansion)
|
||||
return NestedNameSpecifierLoc();
|
||||
return LocInfo.getTemplateQualifierLoc();
|
||||
return SourceLocation();
|
||||
return LocInfo.getTemplateKwLoc();
|
||||
}
|
||||
|
||||
NestedNameSpecifierLoc getTemplateQualifierLoc() const;
|
||||
|
||||
SourceLocation getTemplateNameLoc() const {
|
||||
if (Argument.getKind() != TemplateArgument::Template &&
|
||||
Argument.getKind() != TemplateArgument::TemplateExpansion)
|
||||
|
@ -14,7 +14,7 @@
|
||||
#define LLVM_CLANG_AST_TEMPLATENAME_H
|
||||
|
||||
#include "clang/AST/DependenceFlags.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/NestedNameSpecifierBase.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Basic/OperatorKinds.h"
|
||||
#include "clang/Basic/UnsignedOrNone.h"
|
||||
@ -335,10 +335,18 @@ public:
|
||||
/// structure, if any.
|
||||
QualifiedTemplateName *getAsQualifiedTemplateName() const;
|
||||
|
||||
/// Retrieve the underlying qualified template name,
|
||||
/// looking through underlying nodes.
|
||||
QualifiedTemplateName *getAsAdjustedQualifiedTemplateName() const;
|
||||
|
||||
/// Retrieve the underlying dependent template name
|
||||
/// structure, if any.
|
||||
DependentTemplateName *getAsDependentTemplateName() const;
|
||||
|
||||
// Retrieve the qualifier stored in either a underlying DependentTemplateName
|
||||
// or QualifiedTemplateName.
|
||||
NestedNameSpecifier getQualifier() const;
|
||||
|
||||
/// Retrieve the using shadow declaration through which the underlying
|
||||
/// template declaration is introduced, if any.
|
||||
UsingShadowDecl *getAsUsingShadowDecl() const;
|
||||
@ -503,7 +511,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
|
||||
/// "template" keyword is always redundant in this case (otherwise,
|
||||
/// the template name would be a dependent name and we would express
|
||||
/// this name with DependentTemplateName).
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier;
|
||||
llvm::PointerIntPair<NestedNameSpecifier, 1, bool> Qualifier;
|
||||
|
||||
/// The underlying template name, it is either
|
||||
/// 1) a Template -- a template declaration that this qualified name refers
|
||||
@ -512,7 +520,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
|
||||
/// using-shadow declaration.
|
||||
TemplateName UnderlyingTemplate;
|
||||
|
||||
QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword,
|
||||
QualifiedTemplateName(NestedNameSpecifier NNS, bool TemplateKeyword,
|
||||
TemplateName Template)
|
||||
: Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) {
|
||||
assert(UnderlyingTemplate.getKind() == TemplateName::Template ||
|
||||
@ -521,7 +529,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode {
|
||||
|
||||
public:
|
||||
/// Return the nested name specifier that qualifies this name.
|
||||
NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
|
||||
NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); }
|
||||
|
||||
/// Whether the template name was prefixed by the "template"
|
||||
/// keyword.
|
||||
@ -534,9 +542,9 @@ public:
|
||||
Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate);
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS,
|
||||
bool TemplateKeyword, TemplateName TN) {
|
||||
ID.AddPointer(NNS);
|
||||
NNS.Profile(ID);
|
||||
ID.AddBoolean(TemplateKeyword);
|
||||
ID.AddPointer(TN.getAsVoidPointer());
|
||||
}
|
||||
@ -585,18 +593,18 @@ class DependentTemplateStorage {
|
||||
///
|
||||
/// The bit stored in this qualifier describes whether the \c Name field
|
||||
/// was preceeded by a template keyword.
|
||||
llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier;
|
||||
llvm::PointerIntPair<NestedNameSpecifier, 1, bool> Qualifier;
|
||||
|
||||
/// The dependent template name.
|
||||
IdentifierOrOverloadedOperator Name;
|
||||
|
||||
public:
|
||||
DependentTemplateStorage(NestedNameSpecifier *Qualifier,
|
||||
DependentTemplateStorage(NestedNameSpecifier Qualifier,
|
||||
IdentifierOrOverloadedOperator Name,
|
||||
bool HasTemplateKeyword);
|
||||
|
||||
/// Return the nested name specifier that qualifies this name.
|
||||
NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
|
||||
NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); }
|
||||
|
||||
IdentifierOrOverloadedOperator getName() const { return Name; }
|
||||
|
||||
@ -609,10 +617,10 @@ public:
|
||||
Profile(ID, getQualifier(), getName(), hasTemplateKeyword());
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS,
|
||||
IdentifierOrOverloadedOperator Name,
|
||||
bool HasTemplateKeyword) {
|
||||
ID.AddPointer(NNS);
|
||||
NNS.Profile(ID);
|
||||
ID.AddBoolean(HasTemplateKeyword);
|
||||
Name.Profile(ID);
|
||||
}
|
||||
|
@ -211,7 +211,7 @@ public:
|
||||
void dumpAccessSpecifier(AccessSpecifier AS);
|
||||
void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C);
|
||||
void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK);
|
||||
void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS);
|
||||
void dumpNestedNameSpecifier(NestedNameSpecifier NNS);
|
||||
void dumpConceptReference(const ConceptReference *R);
|
||||
void dumpTemplateArgument(const TemplateArgument &TA);
|
||||
void dumpBareTemplateName(TemplateName TN);
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user