Skip to content

Commit 26b035d

Browse files
committed
[clang] AST: fix getAs canonicalization of leaf types
Before this patch, the application of getAs and castAs on a leaf type would always produce a canonical type, which is undesirable because some of these types can be sugared. The user expectation is that getAs only removes top level sugar nodes, leaving all the type sugar on the returned node, but it had an optimization intended for type nodes with no sugar: for these, we can skip the expensive traversal of the top level sugar with a simple canonicalization followed by dyn_cast. The problem is that the concept of leaf type does not map well to what is correct to apply this optimization to. This patch replaces the concept of leaf types with 'always canonical' types, and only applies the canonicalization strategy on them. In order to avoid the performance regression this would cause, as most current users do not care about type sugar, this patch also replaces all of these uses with alternative cast functions which operate through canonicalization. * Introduces castAs variants to complement the getAsTagDecl and derived variants. * Introduces getAsEnumDecl and castAsEnumDecl, complementing the current set, so that all TagDecls are covered. * Introduces getAsCanonical and castAsCanonical, for faster casting when only the canonical type is desired. The getAsTagDecl and related functions are not provided inline, because of the circular dependencies that would involve. So this patch causes a small overall performance regression: <img width="1461" height="18" alt="image" src="https://github.com/user-attachments/assets/061dfb14-9506-4623-91ec-0f02f585d1dd" /> This will be fixed in a later patch, bringing the whole thing back to a positive performance improvement overall: <img width="1462" height="18" alt="image" src="https://github.com/user-attachments/assets/c237e68f-f696-44f4-acc6-a7c7ba5b0976" />
1 parent 8b0067d commit 26b035d

File tree

121 files changed

+599
-1015
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+599
-1015
lines changed

clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ approximateStandardConversionSequence(const TheCheck &Check, QualType From,
997997
WorkType = QualType{ToBuiltin, FastQualifiersToApply};
998998
}
999999

1000-
const auto *FromEnum = WorkType->getAs<EnumType>();
1000+
const auto *FromEnum = WorkType->getAsCanonical<EnumType>();
10011001
const auto *ToEnum = To->getAs<EnumType>();
10021002
if (FromEnum && ToNumeric && FromEnum->isUnscopedEnumerationType()) {
10031003
// Unscoped enumerations (or enumerations in C) convert to numerics.

clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,8 @@ void TaggedUnionMemberCountCheck::check(
169169
if (!Root || !UnionField || !TagField)
170170
return;
171171

172-
const auto *UnionDef =
173-
UnionField->getType().getCanonicalType().getTypePtr()->getAsRecordDecl();
174-
const auto *EnumDef = llvm::dyn_cast<EnumDecl>(
175-
TagField->getType().getCanonicalType().getTypePtr()->getAsTagDecl());
176-
177-
assert(UnionDef && "UnionDef is missing!");
178-
assert(EnumDef && "EnumDef is missing!");
179-
if (!UnionDef || !EnumDef)
180-
return;
172+
const auto *UnionDef = UnionField->getType()->castAsRecordDecl();
173+
const auto *EnumDef = TagField->getType()->castAsEnumDecl();
181174

182175
const std::size_t UnionMemberCount = llvm::range_size(UnionDef->fields());
183176
auto [TagCount, CountingEnumConstantDecl] = getNumberOfEnumValues(EnumDef);

clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ AST_MATCHER(ParmVarDecl, isTemplateTypeParameter) {
4545

4646
QualType ParamType =
4747
Node.getType().getNonPackExpansionType()->getPointeeType();
48-
const auto *TemplateType = ParamType->getAs<TemplateTypeParmType>();
48+
const auto *TemplateType = ParamType->getAsCanonical<TemplateTypeParmType>();
4949
if (!TemplateType)
5050
return false;
5151

clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ struct InitializerInsertion {
189189

190190
// Convenience utility to get a RecordDecl from a QualType.
191191
const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
192-
if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
192+
if (const auto *RT = Type->getAsCanonical<RecordType>())
193193
return RT->getOriginalDecl();
194194
return nullptr;
195195
}

clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) {
131131
return;
132132
}
133133
if (const auto *ECD = dyn_cast<EnumConstantDecl>(Used)) {
134-
if (const auto *ET = ECD->getType()->getAs<EnumType>())
134+
if (const auto *ET = ECD->getType()->getAsCanonical<EnumType>())
135135
removeFromFoundDecls(ET->getOriginalDecl());
136136
}
137137
};

clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static bool isLockGuardDecl(const NamedDecl *Decl) {
2828
}
2929

3030
static bool isLockGuard(const QualType &Type) {
31-
if (const auto *Record = Type->getAs<RecordType>())
31+
if (const auto *Record = Type->getAsCanonical<RecordType>())
3232
if (const RecordDecl *Decl = Record->getOriginalDecl())
3333
return isLockGuardDecl(Decl);
3434

clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,10 +413,11 @@ static bool areTypesCompatible(QualType ArgType, QualType ParamType,
413413

414414
// Arithmetic types are interconvertible, except scoped enums.
415415
if (ParamType->isArithmeticType() && ArgType->isArithmeticType()) {
416-
if ((ParamType->isEnumeralType() &&
417-
ParamType->castAs<EnumType>()->getOriginalDecl()->isScoped()) ||
416+
if ((ParamType->isEnumeralType() && ParamType->castAsCanonical<EnumType>()
417+
->getOriginalDecl()
418+
->isScoped()) ||
418419
(ArgType->isEnumeralType() &&
419-
ArgType->castAs<EnumType>()->getOriginalDecl()->isScoped()))
420+
ArgType->castAsCanonical<EnumType>()->getOriginalDecl()->isScoped()))
420421
return false;
421422

422423
return true;

clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,7 @@ ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base,
6666
if (!RecType)
6767
return State::Unknown;
6868

69-
const auto *BaseClass =
70-
cast<CXXRecordDecl>(RecType->getOriginalDecl())->getDefinitionOrSelf();
71-
72-
return analyzeRecord(BaseClass, Kind);
69+
return analyzeRecord(RecType->getAsCXXRecordDecl(), Kind);
7370
}
7471

7572
ExceptionSpecAnalyzer::State

clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,9 @@ bool FormatStringConverter::emitIntegerArgument(
460460
// be passed as its underlying type. However, printf will have forced
461461
// the signedness based on the format string, so we need to do the
462462
// same.
463-
if (const auto *ET = ArgType->getAs<EnumType>()) {
464-
if (const std::optional<std::string> MaybeCastType = castTypeForArgument(
465-
ArgKind,
466-
ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType()))
463+
if (const auto *ED = ArgType->getAsEnumDecl()) {
464+
if (const std::optional<std::string> MaybeCastType =
465+
castTypeForArgument(ArgKind, ED->getIntegerType()))
467466
ArgFixes.emplace_back(
468467
ArgIndex, (Twine("static_cast<") + *MaybeCastType + ">(").str());
469468
else

clang-tools-extra/clangd/Hover.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,8 +454,7 @@ std::optional<std::string> printExprValue(const Expr *E,
454454
Constant.Val.getInt().getSignificantBits() <= 64) {
455455
// Compare to int64_t to avoid bit-width match requirements.
456456
int64_t Val = Constant.Val.getInt().getExtValue();
457-
for (const EnumConstantDecl *ECD :
458-
T->castAs<EnumType>()->getOriginalDecl()->enumerators())
457+
for (const EnumConstantDecl *ECD : T->castAsEnumDecl()->enumerators())
459458
if (ECD->getInitVal() == Val)
460459
return llvm::formatv("{0} ({1})", ECD->getNameAsString(),
461460
printHex(Constant.Val.getInt()))
@@ -832,7 +831,7 @@ std::optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE,
832831
ASTContext &ASTCtx,
833832
const PrintingPolicy &PP) {
834833
QualType OriginThisType = CTE->getType()->getPointeeType();
835-
QualType ClassType = declaredType(OriginThisType->getAsTagDecl());
834+
QualType ClassType = declaredType(OriginThisType->castAsTagDecl());
836835
// For partial specialization class, origin `this` pointee type will be
837836
// parsed as `InjectedClassNameType`, which will ouput template arguments
838837
// like "type-parameter-0-0". So we retrieve user written class type in this

0 commit comments

Comments
 (0)