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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang-tools-extra/clang-tidy/utils/TypeTraits.cpp