xref: /llvm-project/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp (revision 7d2ea6c422d3f5712b7253407005e1a465a76946)
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 
15 namespace clang::tidy::utils::type_traits {
16 
17 namespace {
18 
classHasTrivialCopyAndDestroy(QualType Type)19 bool classHasTrivialCopyAndDestroy(QualType Type) {
20   auto *Record = Type->getAsCXXRecordDecl();
21   return Record && Record->hasDefinition() &&
22          !Record->hasNonTrivialCopyConstructor() &&
23          !Record->hasNonTrivialDestructor();
24 }
25 
hasDeletedCopyConstructor(QualType Type)26 bool 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 
isExpensiveToCopy(QualType Type,const ASTContext & Context)39 std::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 
recordIsTriviallyDefaultConstructible(const RecordDecl & RecordDecl,const ASTContext & Context)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.
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(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.
isTriviallyDefaultConstructible(QualType Type,const ASTContext & Context)90 bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
91   if (Type.isNull())
92     return false;
93 
94   if (Type->isArrayType())
95     return isTriviallyDefaultConstructible(Context.getBaseElementType(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(*RT->getDecl(), Context);
130   }
131 
132   // No other types can match.
133   return false;
134 }
135 
136 // Based on QualType::isDestructedType.
isTriviallyDestructible(QualType Type)137 bool 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 
hasNonTrivialMoveConstructor(QualType Type)150 bool hasNonTrivialMoveConstructor(QualType Type) {
151   auto *Record = Type->getAsCXXRecordDecl();
152   return Record && Record->hasDefinition() &&
153          Record->hasNonTrivialMoveConstructor();
154 }
155 
hasNonTrivialMoveAssignment(QualType Type)156 bool 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