[clang-tidy] ObjC ARC objects should not trigger performance-unnecessary-value-param
[lldb.git] / clang-tools-extra / clang-tidy / utils / TypeTraits.cpp
1 //===--- TypeTraits.cpp - clang-tidy---------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "TypeTraits.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/DeclCXX.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14
15 namespace clang {
16 namespace tidy {
17 namespace utils {
18 namespace type_traits {
19
20 namespace {
21
22 bool classHasTrivialCopyAndDestroy(QualType Type) {
23   auto *Record = Type->getAsCXXRecordDecl();
24   return Record && Record->hasDefinition() &&
25          !Record->hasNonTrivialCopyConstructor() &&
26          !Record->hasNonTrivialDestructor();
27 }
28
29 bool hasDeletedCopyConstructor(QualType Type) {
30   auto *Record = Type->getAsCXXRecordDecl();
31   if (!Record || !Record->hasDefinition())
32     return false;
33   for (const auto *Constructor : Record->ctors()) {
34     if (Constructor->isCopyConstructor() && Constructor->isDeleted())
35       return true;
36   }
37   return false;
38 }
39
40 } // namespace
41
42 llvm::Optional<bool> isExpensiveToCopy(QualType Type,
43                                        const ASTContext &Context) {
44   if (Type->isDependentType() || Type->isIncompleteType())
45     return llvm::None;
46   return !Type.isTriviallyCopyableType(Context) &&
47          !classHasTrivialCopyAndDestroy(Type) &&
48          !hasDeletedCopyConstructor(Type) &&
49          !Type->isObjCLifetimeType();
50 }
51
52 bool recordIsTriviallyDefaultConstructible(const RecordDecl &RecordDecl,
53                                            const ASTContext &Context) {
54   const auto *ClassDecl = dyn_cast<CXXRecordDecl>(&RecordDecl);
55   // Non-C++ records are always trivially constructible.
56   if (!ClassDecl)
57     return true;
58   // A class with a user-provided default constructor is not trivially
59   // constructible.
60   if (ClassDecl->hasUserProvidedDefaultConstructor())
61     return false;
62   // A polymorphic class is not trivially constructible
63   if (ClassDecl->isPolymorphic())
64     return false;
65   // A class is trivially constructible if it has a trivial default constructor.
66   if (ClassDecl->hasTrivialDefaultConstructor())
67     return true;
68
69   // If all its fields are trivially constructible and have no default
70   // initializers.
71   for (const FieldDecl *Field : ClassDecl->fields()) {
72     if (Field->hasInClassInitializer())
73       return false;
74     if (!isTriviallyDefaultConstructible(Field->getType(), Context))
75       return false;
76   }
77   // If all its direct bases are trivially constructible.
78   for (const CXXBaseSpecifier &Base : ClassDecl->bases()) {
79     if (!isTriviallyDefaultConstructible(Base.getType(), Context))
80       return false;
81     if (Base.isVirtual())
82       return false;
83   }
84
85   return true;
86 }
87
88 // Based on QualType::isTrivial.
89 bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context) {
90   if (Type.isNull())
91     return false;
92
93   if (Type->isArrayType())
94     return isTriviallyDefaultConstructible(Context.getBaseElementType(Type),
95                                            Context);
96
97   // Return false for incomplete types after skipping any incomplete array
98   // types which are expressly allowed by the standard and thus our API.
99   if (Type->isIncompleteType())
100     return false;
101
102   if (Context.getLangOpts().ObjCAutoRefCount) {
103     switch (Type.getObjCLifetime()) {
104     case Qualifiers::OCL_ExplicitNone:
105       return true;
106
107     case Qualifiers::OCL_Strong:
108     case Qualifiers::OCL_Weak:
109     case Qualifiers::OCL_Autoreleasing:
110       return false;
111
112     case Qualifiers::OCL_None:
113       if (Type->isObjCLifetimeType())
114         return false;
115       break;
116     }
117   }
118
119   QualType CanonicalType = Type.getCanonicalType();
120   if (CanonicalType->isDependentType())
121     return false;
122
123   // As an extension, Clang treats vector types as Scalar types.
124   if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
125     return true;
126
127   if (const auto *RT = CanonicalType->getAs<RecordType>()) {
128     return recordIsTriviallyDefaultConstructible(*RT->getDecl(), Context);
129   }
130
131   // No other types can match.
132   return false;
133 }
134
135 bool hasNonTrivialMoveConstructor(QualType Type) {
136   auto *Record = Type->getAsCXXRecordDecl();
137   return Record && Record->hasDefinition() &&
138          Record->hasNonTrivialMoveConstructor();
139 }
140
141 bool hasNonTrivialMoveAssignment(QualType Type) {
142   auto *Record = Type->getAsCXXRecordDecl();
143   return Record && Record->hasDefinition() &&
144          Record->hasNonTrivialMoveAssignment();
145 }
146
147 } // namespace type_traits
148 } // namespace utils
149 } // namespace tidy
150 } // namespace clang