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