clang-tools 23.0.0git
TypeTraits.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "TypeTraits.h"
10#include "clang/AST/ASTContext.h"
11#include "clang/AST/DeclCXX.h"
12#include "clang/AST/DeclTemplate.h"
13#include <optional>
14
16
17static bool classHasTrivialCopyAndDestroy(QualType Type) {
18 auto *Record = Type->getAsCXXRecordDecl();
19 return Record && Record->hasDefinition() &&
20 !Record->hasNonTrivialCopyConstructor() &&
21 !Record->hasNonTrivialDestructor();
22}
23
24static bool hasDeletedCopyConstructor(QualType Type) {
25 auto *Record = Type->getAsCXXRecordDecl();
26 if (!Record || !Record->hasDefinition())
27 return false;
28 return llvm::any_of(Record->ctors(), [](const auto *Constructor) {
29 return Constructor->isCopyConstructor() && Constructor->isDeleted();
30 });
31}
32
33std::optional<bool> isExpensiveToCopy(QualType Type,
34 const ASTContext &Context) {
35 if (Type->isDependentType() || Type->isIncompleteType())
36 return std::nullopt;
37 return !Type.isTriviallyCopyableType(Context) &&
39 !hasDeletedCopyConstructor(Type) && !Type->isObjCLifetimeType();
40}
41
42bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl,
43 const ASTContext &Context) {
44 const auto *ClassDecl = dyn_cast<CXXRecordDecl>(&RecordDecl);
45 // Non-C++ records are always trivially constructible.
46 if (!ClassDecl)
47 return true;
48 // It is impossible to determine whether an ill-formed decl is trivially
49 // constructible.
50 if (RecordDecl.isInvalidDecl())
51 return false;
52 // A class with a user-provided default constructor is not trivially
53 // constructible.
54 if (ClassDecl->hasUserProvidedDefaultConstructor())
55 return false;
56 // A polymorphic class is not trivially constructible
57 if (ClassDecl->isPolymorphic())
58 return false;
59 // A class is trivially constructible if it has a trivial default constructor.
60 if (ClassDecl->hasTrivialDefaultConstructor())
61 return true;
62
63 // If all its fields are trivially constructible and have no default
64 // initializers.
65 for (const FieldDecl *Field : ClassDecl->fields()) {
66 if (Field->hasInClassInitializer())
67 return false;
68 if (!isTriviallyDefaultConstructible(Field->getType(), Context))
69 return false;
70 }
71 // If all its direct bases are trivially constructible.
72 return llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &Base) {
73 return isTriviallyDefaultConstructible(Base.getType(), Context) &&
74 !Base.isVirtual();
75 });
76}
77
78// Based on QualType::isTrivial.
79bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
80 if (Type.isNull())
81 return false;
82
83 if (Type->isArrayType())
84 return isTriviallyDefaultConstructible(Context.getBaseElementType(Type),
85 Context);
86
87 // Return false for incomplete types after skipping any incomplete array
88 // types which are expressly allowed by the standard and thus our API.
89 if (Type->isIncompleteType())
90 return false;
91
92 if (Context.getLangOpts().ObjCAutoRefCount) {
93 switch (Type.getObjCLifetime()) {
94 case Qualifiers::OCL_ExplicitNone:
95 return true;
96
97 case Qualifiers::OCL_Strong:
98 case Qualifiers::OCL_Weak:
99 case Qualifiers::OCL_Autoreleasing:
100 return false;
101
102 case Qualifiers::OCL_None:
103 if (Type->isObjCLifetimeType())
104 return false;
105 break;
106 }
107 }
108
109 const QualType CanonicalType = Type.getCanonicalType();
110 if (CanonicalType->isDependentType())
111 return false;
112
113 // As an extension, Clang treats vector types as Scalar types.
114 if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
115 return true;
116
117 if (const auto *RD = CanonicalType->getAsRecordDecl())
118 return recordIsTriviallyDefaultConstructible(*RD, Context);
119
120 // No other types can match.
121 return false;
122}
123
124// Based on QualType::isDestructedType.
125bool isTriviallyDestructible(QualType Type) {
126 if (Type.isNull())
127 return false;
128
129 if (Type->isIncompleteType())
130 return false;
131
132 if (Type.getCanonicalType()->isDependentType())
133 return false;
134
135 return Type.isDestructedType() == QualType::DK_none;
136}
137
138bool hasNonTrivialMoveConstructor(QualType Type) {
139 auto *Record = Type->getAsCXXRecordDecl();
140 return Record && Record->hasDefinition() &&
141 Record->hasNonTrivialMoveConstructor();
142}
143
144bool hasNonTrivialMoveAssignment(QualType Type) {
145 auto *Record = Type->getAsCXXRecordDecl();
146 return Record && Record->hasDefinition() &&
147 Record->hasNonTrivialMoveAssignment();
148}
149
150static bool declIsStdInitializerList(const NamedDecl *D) {
151 return D->isInStdNamespace() && D->getName() == "initializer_list";
152}
153
154bool isStdInitializerList(QualType Type) {
155 Type = Type.getCanonicalType();
156 if (const auto *TS = Type->getAs<TemplateSpecializationType>()) {
157 if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl())
158 return declIsStdInitializerList(TD);
159 }
160 if (const auto *RT = Type->getAs<RecordType>()) {
161 if (const auto *Specialization =
162 dyn_cast_if_present<ClassTemplateSpecializationDecl>(RT->getDecl()))
163 return declIsStdInitializerList(Specialization->getSpecializedTemplate());
164 }
165 return false;
166}
167
168} // namespace clang::tidy::utils::type_traits
bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context)
Returns true if Type is trivially default constructible.
bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, const ASTContext &Context)
Returns true if RecordDecl is trivially default constructible.
std::optional< bool > isExpensiveToCopy(QualType Type, const ASTContext &Context)
Returns true if Type is expensive to copy.
static bool declIsStdInitializerList(const NamedDecl *D)
static bool classHasTrivialCopyAndDestroy(QualType Type)
bool hasNonTrivialMoveAssignment(QualType Type)
Return true if Type has a non-trivial move assignment operator.
bool isStdInitializerList(QualType Type)
Returns true if Type is a std::initializer_list<...> specialization.
static bool hasDeletedCopyConstructor(QualType Type)
bool hasNonTrivialMoveConstructor(QualType Type)
Returns true if Type has a non-trivial move constructor.
bool isTriviallyDestructible(QualType Type)
Returns true if Type is trivially destructible.