//===--- TypeTraits.cpp - clang-tidy---------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/ASTMatchers/ASTMatchFinder.h" namespace clang { namespace tidy { namespace utils { namespace type_traits { namespace { bool classHasTrivialCopyAndDestroy(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && !Record->hasNonTrivialCopyConstructor() && !Record->hasNonTrivialDestructor(); } bool hasDeletedCopyConstructor(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); if (!Record || !Record->hasDefinition()) return false; for (const auto *Constructor : Record->ctors()) { if (Constructor->isCopyConstructor() && Constructor->isDeleted()) return true; } return false; } } // namespace llvm::Optional isExpensiveToCopy(QualType Type, const ASTContext &Context) { if (Type->isDependentType() || Type->isIncompleteType()) return llvm::None; return !Type.isTriviallyCopyableType(Context) && !classHasTrivialCopyAndDestroy(Type) && !hasDeletedCopyConstructor(Type) && !Type->isObjCLifetimeType(); } bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl, const ASTContext &Context) { const auto *ClassDecl = dyn_cast(&RecordDecl); // Non-C++ records are always trivially constructible. if (!ClassDecl) return true; // A class with a user-provided default constructor is not trivially // constructible. if (ClassDecl->hasUserProvidedDefaultConstructor()) return false; // A polymorphic class is not trivially constructible if (ClassDecl->isPolymorphic()) return false; // A class is trivially constructible if it has a trivial default constructor. if (ClassDecl->hasTrivialDefaultConstructor()) return true; // If all its fields are trivially constructible and have no default // initializers. for (const FieldDecl *Field : ClassDecl->fields()) { if (Field->hasInClassInitializer()) return false; if (!isTriviallyDefaultConstructible(Field->getType(), Context)) return false; } // If all its direct bases are trivially constructible. for (const CXXBaseSpecifier &Base : ClassDecl->bases()) { if (!isTriviallyDefaultConstructible(Base.getType(), Context)) return false; if (Base.isVirtual()) return false; } return true; } // Based on QualType::isTrivial. bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) { if (Type.isNull()) return false; if (Type->isArrayType()) return isTriviallyDefaultConstructible(Context.getBaseElementType(Type), Context); // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (Type->isIncompleteType()) return false; if (Context.getLangOpts().ObjCAutoRefCount) { switch (Type.getObjCLifetime()) { case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; case Qualifiers::OCL_None: if (Type->isObjCLifetimeType()) return false; break; } } QualType CanonicalType = Type.getCanonicalType(); if (CanonicalType->isDependentType()) return false; // As an extension, Clang treats vector types as Scalar types. if (CanonicalType->isScalarType() || CanonicalType->isVectorType()) return true; if (const auto *RT = CanonicalType->getAs()) { return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context); } // No other types can match. return false; } bool hasNonTrivialMoveConstructor(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && Record->hasNonTrivialMoveConstructor(); } bool hasNonTrivialMoveAssignment(QualType Type) { auto *Record = Type->getAsCXXRecordDecl(); return Record && Record->hasDefinition() && Record->hasNonTrivialMoveAssignment(); } } // namespace type_traits } // namespace utils } // namespace tidy } // namespace clang