1 //===--- TypeTraits.cpp - clang-tidy---------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "TypeTraits.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 namespace clang::tidy::utils::type_traits
{
19 bool classHasTrivialCopyAndDestroy(QualType Type
) {
20 auto *Record
= Type
->getAsCXXRecordDecl();
21 return Record
&& Record
->hasDefinition() &&
22 !Record
->hasNonTrivialCopyConstructor() &&
23 !Record
->hasNonTrivialDestructor();
26 bool hasDeletedCopyConstructor(QualType Type
) {
27 auto *Record
= Type
->getAsCXXRecordDecl();
28 if (!Record
|| !Record
->hasDefinition())
30 for (const auto *Constructor
: Record
->ctors()) {
31 if (Constructor
->isCopyConstructor() && Constructor
->isDeleted())
39 std::optional
<bool> isExpensiveToCopy(QualType Type
,
40 const ASTContext
&Context
) {
41 if (Type
->isDependentType() || Type
->isIncompleteType())
43 return !Type
.isTriviallyCopyableType(Context
) &&
44 !classHasTrivialCopyAndDestroy(Type
) &&
45 !hasDeletedCopyConstructor(Type
) &&
46 !Type
->isObjCLifetimeType();
49 bool recordIsTriviallyDefaultConstructible(const RecordDecl
&RecordDecl
,
50 const ASTContext
&Context
) {
51 const auto *ClassDecl
= dyn_cast
<CXXRecordDecl
>(&RecordDecl
);
52 // Non-C++ records are always trivially constructible.
55 // It is impossible to determine whether an ill-formed decl is trivially
57 if (RecordDecl
.isInvalidDecl())
59 // A class with a user-provided default constructor is not trivially
61 if (ClassDecl
->hasUserProvidedDefaultConstructor())
63 // A polymorphic class is not trivially constructible
64 if (ClassDecl
->isPolymorphic())
66 // A class is trivially constructible if it has a trivial default constructor.
67 if (ClassDecl
->hasTrivialDefaultConstructor())
70 // If all its fields are trivially constructible and have no default
72 for (const FieldDecl
*Field
: ClassDecl
->fields()) {
73 if (Field
->hasInClassInitializer())
75 if (!isTriviallyDefaultConstructible(Field
->getType(), Context
))
78 // If all its direct bases are trivially constructible.
79 for (const CXXBaseSpecifier
&Base
: ClassDecl
->bases()) {
80 if (!isTriviallyDefaultConstructible(Base
.getType(), Context
))
89 // Based on QualType::isTrivial.
90 bool isTriviallyDefaultConstructible(QualType Type
, const ASTContext
&Context
) {
94 if (Type
->isArrayType())
95 return isTriviallyDefaultConstructible(Context
.getBaseElementType(Type
),
98 // Return false for incomplete types after skipping any incomplete array
99 // types which are expressly allowed by the standard and thus our API.
100 if (Type
->isIncompleteType())
103 if (Context
.getLangOpts().ObjCAutoRefCount
) {
104 switch (Type
.getObjCLifetime()) {
105 case Qualifiers::OCL_ExplicitNone
:
108 case Qualifiers::OCL_Strong
:
109 case Qualifiers::OCL_Weak
:
110 case Qualifiers::OCL_Autoreleasing
:
113 case Qualifiers::OCL_None
:
114 if (Type
->isObjCLifetimeType())
120 QualType CanonicalType
= Type
.getCanonicalType();
121 if (CanonicalType
->isDependentType())
124 // As an extension, Clang treats vector types as Scalar types.
125 if (CanonicalType
->isScalarType() || CanonicalType
->isVectorType())
128 if (const auto *RT
= CanonicalType
->getAs
<RecordType
>()) {
129 return recordIsTriviallyDefaultConstructible(*RT
->getDecl(), Context
);
132 // No other types can match.
136 // Based on QualType::isDestructedType.
137 bool isTriviallyDestructible(QualType Type
) {
141 if (Type
->isIncompleteType())
144 if (Type
.getCanonicalType()->isDependentType())
147 return Type
.isDestructedType() == QualType::DK_none
;
150 bool hasNonTrivialMoveConstructor(QualType Type
) {
151 auto *Record
= Type
->getAsCXXRecordDecl();
152 return Record
&& Record
->hasDefinition() &&
153 Record
->hasNonTrivialMoveConstructor();
156 bool hasNonTrivialMoveAssignment(QualType Type
) {
157 auto *Record
= Type
->getAsCXXRecordDecl();
158 return Record
&& Record
->hasDefinition() &&
159 Record
->hasNonTrivialMoveAssignment();
162 } // namespace clang::tidy::utils::type_traits