[InstCombine] Drop range attributes in `foldBitCeil` (#116641)
[llvm-project.git] / clang-tools-extra / clang-tidy / utils / TypeTraits.cpp
blob270b438c00c18ed1c6469f742d2d2ac38c988fd1
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 //===----------------------------------------------------------------------===//
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>
15 namespace clang::tidy::utils::type_traits {
17 namespace {
19 bool classHasTrivialCopyAndDestroy(QualType Type) {
20 auto *Record = Type->getAsCXXRecordDecl();
21 return Record && Record->hasDefinition() &&
22 !Record->hasNonTrivialCopyConstructor() &&
23 !Record->hasNonTrivialDestructor();
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;
34 return false;
37 } // namespace
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();
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;
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;
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;
86 return true;
89 // Based on QualType::isTrivial.
90 bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
91 if (Type.isNull())
92 return false;
94 if (Type->isArrayType())
95 return isTriviallyDefaultConstructible(Context.getBaseElementType(Type),
96 Context);
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;
103 if (Context.getLangOpts().ObjCAutoRefCount) {
104 switch (Type.getObjCLifetime()) {
105 case Qualifiers::OCL_ExplicitNone:
106 return true;
108 case Qualifiers::OCL_Strong:
109 case Qualifiers::OCL_Weak:
110 case Qualifiers::OCL_Autoreleasing:
111 return false;
113 case Qualifiers::OCL_None:
114 if (Type->isObjCLifetimeType())
115 return false;
116 break;
120 QualType CanonicalType = Type.getCanonicalType();
121 if (CanonicalType->isDependentType())
122 return false;
124 // As an extension, Clang treats vector types as Scalar types.
125 if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
126 return true;
128 if (const auto *RT = CanonicalType->getAs<RecordType>()) {
129 return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context);
132 // No other types can match.
133 return false;
136 // Based on QualType::isDestructedType.
137 bool isTriviallyDestructible(QualType Type) {
138 if (Type.isNull())
139 return false;
141 if (Type->isIncompleteType())
142 return false;
144 if (Type.getCanonicalType()->isDependentType())
145 return false;
147 return Type.isDestructedType() == QualType::DK_none;
150 bool hasNonTrivialMoveConstructor(QualType Type) {
151 auto *Record = Type->getAsCXXRecordDecl();
152 return Record && Record->hasDefinition() &&
153 Record->hasNonTrivialMoveConstructor();
156 bool hasNonTrivialMoveAssignment(QualType Type) {
157 auto *Record = Type->getAsCXXRecordDecl();
158 return Record && Record->hasDefinition() &&
159 Record->hasNonTrivialMoveAssignment();
162 } // namespace clang::tidy::utils::type_traits