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

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