157 lines · cpp
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-exception6//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 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) &&39 !classHasTrivialCopyAndDestroy(Type) &&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 trivially50 // constructible.51 if (RecordDecl.isInvalidDecl())52 return false;53 // A class with a user-provided default constructor is not trivially54 // constructible.55 if (ClassDecl->hasUserProvidedDefaultConstructor())56 return false;57 // A polymorphic class is not trivially constructible58 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 default65 // 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 array93 // 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 const 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_traits157