[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / clang-tidy / utils / ExceptionSpecAnalyzer.cpp
blob40a3916fde478266de43e0cb40c194a01b35505f
1 //===--- ExceptionSpecAnalyzer.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 "ExceptionSpecAnalyzer.h"
11 #include "clang/AST/Expr.h"
13 namespace clang::tidy::utils {
15 ExceptionSpecAnalyzer::State
16 ExceptionSpecAnalyzer::analyze(const FunctionDecl *FuncDecl) {
17 ExceptionSpecAnalyzer::State State;
19 // Check if the function has already been analyzed and reuse that result.
20 const auto CacheEntry = FunctionCache.find(FuncDecl);
21 if (CacheEntry == FunctionCache.end()) {
22 State = analyzeImpl(FuncDecl);
24 // Cache the result of the analysis.
25 FunctionCache.try_emplace(FuncDecl, State);
26 } else
27 State = CacheEntry->getSecond();
29 return State;
32 ExceptionSpecAnalyzer::State
33 ExceptionSpecAnalyzer::analyzeUnresolvedOrDefaulted(
34 const CXXMethodDecl *MethodDecl, const FunctionProtoType *FuncProto) {
35 if (!FuncProto || !MethodDecl)
36 return State::Unknown;
38 const DefaultableMemberKind Kind = getDefaultableMemberKind(MethodDecl);
40 if (Kind == DefaultableMemberKind::None)
41 return State::Unknown;
43 return analyzeRecord(MethodDecl->getParent(), Kind, SkipMethods::Yes);
46 ExceptionSpecAnalyzer::State
47 ExceptionSpecAnalyzer::analyzeFieldDecl(const FieldDecl *FDecl,
48 DefaultableMemberKind Kind) {
49 if (!FDecl)
50 return State::Unknown;
52 if (const CXXRecordDecl *RecDecl =
53 FDecl->getType()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl())
54 return analyzeRecord(RecDecl, Kind);
56 // Trivial types do not throw
57 if (FDecl->getType().isTrivialType(FDecl->getASTContext()))
58 return State::NotThrowing;
60 return State::Unknown;
63 ExceptionSpecAnalyzer::State
64 ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base,
65 DefaultableMemberKind Kind) {
66 const auto *RecType = Base.getType()->getAs<RecordType>();
67 if (!RecType)
68 return State::Unknown;
70 const auto *BaseClass = cast<CXXRecordDecl>(RecType->getDecl());
72 return analyzeRecord(BaseClass, Kind);
75 ExceptionSpecAnalyzer::State
76 ExceptionSpecAnalyzer::analyzeRecord(const CXXRecordDecl *RecordDecl,
77 DefaultableMemberKind Kind,
78 SkipMethods SkipMethods) {
79 if (!RecordDecl)
80 return State::Unknown;
82 // Trivial implies noexcept
83 if (hasTrivialMemberKind(RecordDecl, Kind))
84 return State::NotThrowing;
86 if (SkipMethods == SkipMethods::No)
87 for (const auto *MethodDecl : RecordDecl->methods())
88 if (getDefaultableMemberKind(MethodDecl) == Kind)
89 return analyze(MethodDecl);
91 for (const auto &BaseSpec : RecordDecl->bases()) {
92 State Result = analyzeBase(BaseSpec, Kind);
93 if (Result == State::Throwing || Result == State::Unknown)
94 return Result;
97 for (const auto &BaseSpec : RecordDecl->vbases()) {
98 State Result = analyzeBase(BaseSpec, Kind);
99 if (Result == State::Throwing || Result == State::Unknown)
100 return Result;
103 for (const auto *FDecl : RecordDecl->fields())
104 if (!FDecl->isInvalidDecl() && !FDecl->isUnnamedBitfield()) {
105 State Result = analyzeFieldDecl(FDecl, Kind);
106 if (Result == State::Throwing || Result == State::Unknown)
107 return Result;
110 return State::NotThrowing;
113 ExceptionSpecAnalyzer::State
114 ExceptionSpecAnalyzer::analyzeImpl(const FunctionDecl *FuncDecl) {
115 const auto *FuncProto = FuncDecl->getType()->getAs<FunctionProtoType>();
116 if (!FuncProto)
117 return State::Unknown;
119 const ExceptionSpecificationType EST = FuncProto->getExceptionSpecType();
121 if (EST == EST_Unevaluated || (EST == EST_None && FuncDecl->isDefaulted()))
122 return analyzeUnresolvedOrDefaulted(cast<CXXMethodDecl>(FuncDecl),
123 FuncProto);
125 return analyzeFunctionEST(FuncDecl, FuncProto);
128 ExceptionSpecAnalyzer::State
129 ExceptionSpecAnalyzer::analyzeFunctionEST(const FunctionDecl *FuncDecl,
130 const FunctionProtoType *FuncProto) {
131 if (!FuncDecl || !FuncProto)
132 return State::Unknown;
134 if (isUnresolvedExceptionSpec(FuncProto->getExceptionSpecType()))
135 return State::Unknown;
137 // A non defaulted destructor without the noexcept specifier is still noexcept
138 if (isa<CXXDestructorDecl>(FuncDecl) &&
139 FuncDecl->getExceptionSpecType() == EST_None)
140 return State::NotThrowing;
142 switch (FuncProto->canThrow()) {
143 case CT_Cannot:
144 return State::NotThrowing;
145 case CT_Dependent: {
146 const Expr *NoexceptExpr = FuncProto->getNoexceptExpr();
147 bool Result;
148 return (NoexceptExpr && !NoexceptExpr->isValueDependent() &&
149 NoexceptExpr->EvaluateAsBooleanCondition(
150 Result, FuncDecl->getASTContext(), true) &&
151 Result)
152 ? State::NotThrowing
153 : State::Throwing;
155 default:
156 return State::Throwing;
160 bool ExceptionSpecAnalyzer::hasTrivialMemberKind(const CXXRecordDecl *RecDecl,
161 DefaultableMemberKind Kind) {
162 if (!RecDecl)
163 return false;
165 switch (Kind) {
166 case DefaultableMemberKind::DefaultConstructor:
167 return RecDecl->hasTrivialDefaultConstructor();
168 case DefaultableMemberKind::CopyConstructor:
169 return RecDecl->hasTrivialCopyConstructor();
170 case DefaultableMemberKind::MoveConstructor:
171 return RecDecl->hasTrivialMoveConstructor();
172 case DefaultableMemberKind::CopyAssignment:
173 return RecDecl->hasTrivialCopyAssignment();
174 case DefaultableMemberKind::MoveAssignment:
175 return RecDecl->hasTrivialMoveAssignment();
176 case DefaultableMemberKind::Destructor:
177 return RecDecl->hasTrivialDestructor();
179 default:
180 return false;
184 bool ExceptionSpecAnalyzer::isConstructor(DefaultableMemberKind Kind) {
185 switch (Kind) {
186 case DefaultableMemberKind::DefaultConstructor:
187 case DefaultableMemberKind::CopyConstructor:
188 case DefaultableMemberKind::MoveConstructor:
189 return true;
191 default:
192 return false;
196 bool ExceptionSpecAnalyzer::isSpecialMember(DefaultableMemberKind Kind) {
197 switch (Kind) {
198 case DefaultableMemberKind::DefaultConstructor:
199 case DefaultableMemberKind::CopyConstructor:
200 case DefaultableMemberKind::MoveConstructor:
201 case DefaultableMemberKind::CopyAssignment:
202 case DefaultableMemberKind::MoveAssignment:
203 case DefaultableMemberKind::Destructor:
204 return true;
205 default:
206 return false;
210 bool ExceptionSpecAnalyzer::isComparison(DefaultableMemberKind Kind) {
211 switch (Kind) {
212 case DefaultableMemberKind::CompareEqual:
213 case DefaultableMemberKind::CompareNotEqual:
214 case DefaultableMemberKind::CompareRelational:
215 case DefaultableMemberKind::CompareThreeWay:
216 return true;
217 default:
218 return false;
222 ExceptionSpecAnalyzer::DefaultableMemberKind
223 ExceptionSpecAnalyzer::getDefaultableMemberKind(const FunctionDecl *FuncDecl) {
224 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl)) {
225 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
226 if (Ctor->isDefaultConstructor())
227 return DefaultableMemberKind::DefaultConstructor;
229 if (Ctor->isCopyConstructor())
230 return DefaultableMemberKind::CopyConstructor;
232 if (Ctor->isMoveConstructor())
233 return DefaultableMemberKind::MoveConstructor;
236 if (MethodDecl->isCopyAssignmentOperator())
237 return DefaultableMemberKind::CopyAssignment;
239 if (MethodDecl->isMoveAssignmentOperator())
240 return DefaultableMemberKind::MoveAssignment;
242 if (isa<CXXDestructorDecl>(FuncDecl))
243 return DefaultableMemberKind::Destructor;
246 const LangOptions &LangOpts = FuncDecl->getLangOpts();
248 switch (FuncDecl->getDeclName().getCXXOverloadedOperator()) {
249 case OO_EqualEqual:
250 return DefaultableMemberKind::CompareEqual;
252 case OO_ExclaimEqual:
253 return DefaultableMemberKind::CompareNotEqual;
255 case OO_Spaceship:
256 // No point allowing this if <=> doesn't exist in the current language mode.
257 if (!LangOpts.CPlusPlus20)
258 break;
259 return DefaultableMemberKind::CompareThreeWay;
261 case OO_Less:
262 case OO_LessEqual:
263 case OO_Greater:
264 case OO_GreaterEqual:
265 // No point allowing this if <=> doesn't exist in the current language mode.
266 if (!LangOpts.CPlusPlus20)
267 break;
268 return DefaultableMemberKind::CompareRelational;
270 default:
271 break;
274 // Not a defaultable member kind
275 return DefaultableMemberKind::None;
278 } // namespace clang::tidy::utils