15abe338fSAMS21 //===--- ExceptionSpecAnalyzer.cpp - clang-tidy ---------------------------===//
25abe338fSAMS21 //
35abe338fSAMS21 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45abe338fSAMS21 // See https://llvm.org/LICENSE.txt for license information.
55abe338fSAMS21 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65abe338fSAMS21 //
75abe338fSAMS21 //===----------------------------------------------------------------------===//
85abe338fSAMS21
95abe338fSAMS21 #include "ExceptionSpecAnalyzer.h"
105abe338fSAMS21
115abe338fSAMS21 #include "clang/AST/Expr.h"
125abe338fSAMS21
135abe338fSAMS21 namespace clang::tidy::utils {
145abe338fSAMS21
155abe338fSAMS21 ExceptionSpecAnalyzer::State
analyze(const FunctionDecl * FuncDecl)165abe338fSAMS21 ExceptionSpecAnalyzer::analyze(const FunctionDecl *FuncDecl) {
175abe338fSAMS21 // Check if the function has already been analyzed and reuse that result.
185abe338fSAMS21 const auto CacheEntry = FunctionCache.find(FuncDecl);
195abe338fSAMS21 if (CacheEntry == FunctionCache.end()) {
20cbdc3e1bSPiotr Zegar ExceptionSpecAnalyzer::State State = analyzeImpl(FuncDecl);
215abe338fSAMS21
225abe338fSAMS21 // Cache the result of the analysis.
235abe338fSAMS21 FunctionCache.try_emplace(FuncDecl, State);
245abe338fSAMS21 return State;
255abe338fSAMS21 }
265abe338fSAMS21
27cbdc3e1bSPiotr Zegar return CacheEntry->getSecond();
28cbdc3e1bSPiotr Zegar }
29cbdc3e1bSPiotr Zegar
305abe338fSAMS21 ExceptionSpecAnalyzer::State
analyzeUnresolvedOrDefaulted(const CXXMethodDecl * MethodDecl,const FunctionProtoType * FuncProto)315abe338fSAMS21 ExceptionSpecAnalyzer::analyzeUnresolvedOrDefaulted(
325abe338fSAMS21 const CXXMethodDecl *MethodDecl, const FunctionProtoType *FuncProto) {
335abe338fSAMS21 if (!FuncProto || !MethodDecl)
345abe338fSAMS21 return State::Unknown;
355abe338fSAMS21
365abe338fSAMS21 const DefaultableMemberKind Kind = getDefaultableMemberKind(MethodDecl);
375abe338fSAMS21
385abe338fSAMS21 if (Kind == DefaultableMemberKind::None)
395abe338fSAMS21 return State::Unknown;
405abe338fSAMS21
415abe338fSAMS21 return analyzeRecord(MethodDecl->getParent(), Kind, SkipMethods::Yes);
425abe338fSAMS21 }
435abe338fSAMS21
445abe338fSAMS21 ExceptionSpecAnalyzer::State
analyzeFieldDecl(const FieldDecl * FDecl,DefaultableMemberKind Kind)455abe338fSAMS21 ExceptionSpecAnalyzer::analyzeFieldDecl(const FieldDecl *FDecl,
465abe338fSAMS21 DefaultableMemberKind Kind) {
475abe338fSAMS21 if (!FDecl)
485abe338fSAMS21 return State::Unknown;
495abe338fSAMS21
505abe338fSAMS21 if (const CXXRecordDecl *RecDecl =
515abe338fSAMS21 FDecl->getType()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl())
525abe338fSAMS21 return analyzeRecord(RecDecl, Kind);
535abe338fSAMS21
545abe338fSAMS21 // Trivial types do not throw
555abe338fSAMS21 if (FDecl->getType().isTrivialType(FDecl->getASTContext()))
565abe338fSAMS21 return State::NotThrowing;
575abe338fSAMS21
585abe338fSAMS21 return State::Unknown;
595abe338fSAMS21 }
605abe338fSAMS21
615abe338fSAMS21 ExceptionSpecAnalyzer::State
analyzeBase(const CXXBaseSpecifier & Base,DefaultableMemberKind Kind)625abe338fSAMS21 ExceptionSpecAnalyzer::analyzeBase(const CXXBaseSpecifier &Base,
635abe338fSAMS21 DefaultableMemberKind Kind) {
645abe338fSAMS21 const auto *RecType = Base.getType()->getAs<RecordType>();
655abe338fSAMS21 if (!RecType)
665abe338fSAMS21 return State::Unknown;
675abe338fSAMS21
685abe338fSAMS21 const auto *BaseClass = cast<CXXRecordDecl>(RecType->getDecl());
695abe338fSAMS21
705abe338fSAMS21 return analyzeRecord(BaseClass, Kind);
715abe338fSAMS21 }
725abe338fSAMS21
735abe338fSAMS21 ExceptionSpecAnalyzer::State
analyzeRecord(const CXXRecordDecl * RecordDecl,DefaultableMemberKind Kind,SkipMethods SkipMethods)745abe338fSAMS21 ExceptionSpecAnalyzer::analyzeRecord(const CXXRecordDecl *RecordDecl,
755abe338fSAMS21 DefaultableMemberKind Kind,
765abe338fSAMS21 SkipMethods SkipMethods) {
775abe338fSAMS21 if (!RecordDecl)
785abe338fSAMS21 return State::Unknown;
795abe338fSAMS21
805abe338fSAMS21 // Trivial implies noexcept
815abe338fSAMS21 if (hasTrivialMemberKind(RecordDecl, Kind))
825abe338fSAMS21 return State::NotThrowing;
835abe338fSAMS21
845abe338fSAMS21 if (SkipMethods == SkipMethods::No)
855abe338fSAMS21 for (const auto *MethodDecl : RecordDecl->methods())
865abe338fSAMS21 if (getDefaultableMemberKind(MethodDecl) == Kind)
875abe338fSAMS21 return analyze(MethodDecl);
885abe338fSAMS21
895abe338fSAMS21 for (const auto &BaseSpec : RecordDecl->bases()) {
905abe338fSAMS21 State Result = analyzeBase(BaseSpec, Kind);
915abe338fSAMS21 if (Result == State::Throwing || Result == State::Unknown)
925abe338fSAMS21 return Result;
935abe338fSAMS21 }
945abe338fSAMS21
955abe338fSAMS21 for (const auto &BaseSpec : RecordDecl->vbases()) {
965abe338fSAMS21 State Result = analyzeBase(BaseSpec, Kind);
975abe338fSAMS21 if (Result == State::Throwing || Result == State::Unknown)
985abe338fSAMS21 return Result;
995abe338fSAMS21 }
1005abe338fSAMS21
1015abe338fSAMS21 for (const auto *FDecl : RecordDecl->fields())
102*3d56ea05STimm Baeder if (!FDecl->isInvalidDecl() && !FDecl->isUnnamedBitField()) {
1035abe338fSAMS21 State Result = analyzeFieldDecl(FDecl, Kind);
1045abe338fSAMS21 if (Result == State::Throwing || Result == State::Unknown)
1055abe338fSAMS21 return Result;
1065abe338fSAMS21 }
1075abe338fSAMS21
1085abe338fSAMS21 return State::NotThrowing;
1095abe338fSAMS21 }
1105abe338fSAMS21
1115abe338fSAMS21 ExceptionSpecAnalyzer::State
analyzeImpl(const FunctionDecl * FuncDecl)1125abe338fSAMS21 ExceptionSpecAnalyzer::analyzeImpl(const FunctionDecl *FuncDecl) {
1135abe338fSAMS21 const auto *FuncProto = FuncDecl->getType()->getAs<FunctionProtoType>();
1145abe338fSAMS21 if (!FuncProto)
1155abe338fSAMS21 return State::Unknown;
1165abe338fSAMS21
1175abe338fSAMS21 const ExceptionSpecificationType EST = FuncProto->getExceptionSpecType();
1185abe338fSAMS21
1195abe338fSAMS21 if (EST == EST_Unevaluated || (EST == EST_None && FuncDecl->isDefaulted()))
1205abe338fSAMS21 return analyzeUnresolvedOrDefaulted(cast<CXXMethodDecl>(FuncDecl),
1215abe338fSAMS21 FuncProto);
1225abe338fSAMS21
1235abe338fSAMS21 return analyzeFunctionEST(FuncDecl, FuncProto);
1245abe338fSAMS21 }
1255abe338fSAMS21
1265abe338fSAMS21 ExceptionSpecAnalyzer::State
analyzeFunctionEST(const FunctionDecl * FuncDecl,const FunctionProtoType * FuncProto)1275abe338fSAMS21 ExceptionSpecAnalyzer::analyzeFunctionEST(const FunctionDecl *FuncDecl,
1285abe338fSAMS21 const FunctionProtoType *FuncProto) {
1295abe338fSAMS21 if (!FuncDecl || !FuncProto)
1305abe338fSAMS21 return State::Unknown;
1315abe338fSAMS21
1325abe338fSAMS21 if (isUnresolvedExceptionSpec(FuncProto->getExceptionSpecType()))
1335abe338fSAMS21 return State::Unknown;
1345abe338fSAMS21
135474a2b93SAMS21 // A non defaulted destructor without the noexcept specifier is still noexcept
136474a2b93SAMS21 if (isa<CXXDestructorDecl>(FuncDecl) &&
137474a2b93SAMS21 FuncDecl->getExceptionSpecType() == EST_None)
138474a2b93SAMS21 return State::NotThrowing;
139474a2b93SAMS21
1405abe338fSAMS21 switch (FuncProto->canThrow()) {
1415abe338fSAMS21 case CT_Cannot:
1425abe338fSAMS21 return State::NotThrowing;
1435abe338fSAMS21 case CT_Dependent: {
1445abe338fSAMS21 const Expr *NoexceptExpr = FuncProto->getNoexceptExpr();
145f9bd62fbSAMS21 if (!NoexceptExpr)
146f9bd62fbSAMS21 return State::NotThrowing;
147f9bd62fbSAMS21
148f9bd62fbSAMS21 // We can't resolve value dependence so just return unknown
149f9bd62fbSAMS21 if (NoexceptExpr->isValueDependent())
150f9bd62fbSAMS21 return State::Unknown;
151f9bd62fbSAMS21
152f9bd62fbSAMS21 // Try to evaluate the expression to a boolean value
153cbdc3e1bSPiotr Zegar bool Result = false;
154f9bd62fbSAMS21 if (NoexceptExpr->EvaluateAsBooleanCondition(
155f9bd62fbSAMS21 Result, FuncDecl->getASTContext(), true))
156f9bd62fbSAMS21 return Result ? State::NotThrowing : State::Throwing;
157f9bd62fbSAMS21
158f9bd62fbSAMS21 // The noexcept expression is not value dependent but we can't evaluate it
159f9bd62fbSAMS21 // as a boolean condition so we have no idea if its throwing or not
160f9bd62fbSAMS21 return State::Unknown;
1615abe338fSAMS21 }
1625abe338fSAMS21 default:
1635abe338fSAMS21 return State::Throwing;
1645abe338fSAMS21 };
1655abe338fSAMS21 }
1665abe338fSAMS21
hasTrivialMemberKind(const CXXRecordDecl * RecDecl,DefaultableMemberKind Kind)1675abe338fSAMS21 bool ExceptionSpecAnalyzer::hasTrivialMemberKind(const CXXRecordDecl *RecDecl,
1685abe338fSAMS21 DefaultableMemberKind Kind) {
1695abe338fSAMS21 if (!RecDecl)
1705abe338fSAMS21 return false;
1715abe338fSAMS21
1725abe338fSAMS21 switch (Kind) {
1735abe338fSAMS21 case DefaultableMemberKind::DefaultConstructor:
1745abe338fSAMS21 return RecDecl->hasTrivialDefaultConstructor();
1755abe338fSAMS21 case DefaultableMemberKind::CopyConstructor:
1765abe338fSAMS21 return RecDecl->hasTrivialCopyConstructor();
1775abe338fSAMS21 case DefaultableMemberKind::MoveConstructor:
1785abe338fSAMS21 return RecDecl->hasTrivialMoveConstructor();
1795abe338fSAMS21 case DefaultableMemberKind::CopyAssignment:
1805abe338fSAMS21 return RecDecl->hasTrivialCopyAssignment();
1815abe338fSAMS21 case DefaultableMemberKind::MoveAssignment:
1825abe338fSAMS21 return RecDecl->hasTrivialMoveAssignment();
1835abe338fSAMS21 case DefaultableMemberKind::Destructor:
1845abe338fSAMS21 return RecDecl->hasTrivialDestructor();
1855abe338fSAMS21
1865abe338fSAMS21 default:
1875abe338fSAMS21 return false;
1885abe338fSAMS21 }
1895abe338fSAMS21 }
1905abe338fSAMS21
isConstructor(DefaultableMemberKind Kind)1915abe338fSAMS21 bool ExceptionSpecAnalyzer::isConstructor(DefaultableMemberKind Kind) {
1925abe338fSAMS21 switch (Kind) {
1935abe338fSAMS21 case DefaultableMemberKind::DefaultConstructor:
1945abe338fSAMS21 case DefaultableMemberKind::CopyConstructor:
1955abe338fSAMS21 case DefaultableMemberKind::MoveConstructor:
1965abe338fSAMS21 return true;
1975abe338fSAMS21
1985abe338fSAMS21 default:
1995abe338fSAMS21 return false;
2005abe338fSAMS21 }
2015abe338fSAMS21 }
2025abe338fSAMS21
isSpecialMember(DefaultableMemberKind Kind)2035abe338fSAMS21 bool ExceptionSpecAnalyzer::isSpecialMember(DefaultableMemberKind Kind) {
2045abe338fSAMS21 switch (Kind) {
2055abe338fSAMS21 case DefaultableMemberKind::DefaultConstructor:
2065abe338fSAMS21 case DefaultableMemberKind::CopyConstructor:
2075abe338fSAMS21 case DefaultableMemberKind::MoveConstructor:
2085abe338fSAMS21 case DefaultableMemberKind::CopyAssignment:
2095abe338fSAMS21 case DefaultableMemberKind::MoveAssignment:
2105abe338fSAMS21 case DefaultableMemberKind::Destructor:
2115abe338fSAMS21 return true;
2125abe338fSAMS21 default:
2135abe338fSAMS21 return false;
2145abe338fSAMS21 }
2155abe338fSAMS21 }
2165abe338fSAMS21
isComparison(DefaultableMemberKind Kind)2175abe338fSAMS21 bool ExceptionSpecAnalyzer::isComparison(DefaultableMemberKind Kind) {
2185abe338fSAMS21 switch (Kind) {
2195abe338fSAMS21 case DefaultableMemberKind::CompareEqual:
2205abe338fSAMS21 case DefaultableMemberKind::CompareNotEqual:
2215abe338fSAMS21 case DefaultableMemberKind::CompareRelational:
2225abe338fSAMS21 case DefaultableMemberKind::CompareThreeWay:
2235abe338fSAMS21 return true;
2245abe338fSAMS21 default:
2255abe338fSAMS21 return false;
2265abe338fSAMS21 }
2275abe338fSAMS21 }
2285abe338fSAMS21
2295abe338fSAMS21 ExceptionSpecAnalyzer::DefaultableMemberKind
getDefaultableMemberKind(const FunctionDecl * FuncDecl)2305abe338fSAMS21 ExceptionSpecAnalyzer::getDefaultableMemberKind(const FunctionDecl *FuncDecl) {
2315abe338fSAMS21 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl)) {
2325abe338fSAMS21 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
2335abe338fSAMS21 if (Ctor->isDefaultConstructor())
2345abe338fSAMS21 return DefaultableMemberKind::DefaultConstructor;
2355abe338fSAMS21
2365abe338fSAMS21 if (Ctor->isCopyConstructor())
2375abe338fSAMS21 return DefaultableMemberKind::CopyConstructor;
2385abe338fSAMS21
2395abe338fSAMS21 if (Ctor->isMoveConstructor())
2405abe338fSAMS21 return DefaultableMemberKind::MoveConstructor;
2415abe338fSAMS21 }
2425abe338fSAMS21
2435abe338fSAMS21 if (MethodDecl->isCopyAssignmentOperator())
2445abe338fSAMS21 return DefaultableMemberKind::CopyAssignment;
2455abe338fSAMS21
2465abe338fSAMS21 if (MethodDecl->isMoveAssignmentOperator())
2475abe338fSAMS21 return DefaultableMemberKind::MoveAssignment;
2485abe338fSAMS21
2495abe338fSAMS21 if (isa<CXXDestructorDecl>(FuncDecl))
2505abe338fSAMS21 return DefaultableMemberKind::Destructor;
2515abe338fSAMS21 }
2525abe338fSAMS21
2535abe338fSAMS21 const LangOptions &LangOpts = FuncDecl->getLangOpts();
2545abe338fSAMS21
2555abe338fSAMS21 switch (FuncDecl->getDeclName().getCXXOverloadedOperator()) {
2565abe338fSAMS21 case OO_EqualEqual:
2575abe338fSAMS21 return DefaultableMemberKind::CompareEqual;
2585abe338fSAMS21
2595abe338fSAMS21 case OO_ExclaimEqual:
2605abe338fSAMS21 return DefaultableMemberKind::CompareNotEqual;
2615abe338fSAMS21
2625abe338fSAMS21 case OO_Spaceship:
2635abe338fSAMS21 // No point allowing this if <=> doesn't exist in the current language mode.
2645abe338fSAMS21 if (!LangOpts.CPlusPlus20)
2655abe338fSAMS21 break;
2665abe338fSAMS21 return DefaultableMemberKind::CompareThreeWay;
2675abe338fSAMS21
2685abe338fSAMS21 case OO_Less:
2695abe338fSAMS21 case OO_LessEqual:
2705abe338fSAMS21 case OO_Greater:
2715abe338fSAMS21 case OO_GreaterEqual:
2725abe338fSAMS21 // No point allowing this if <=> doesn't exist in the current language mode.
2735abe338fSAMS21 if (!LangOpts.CPlusPlus20)
2745abe338fSAMS21 break;
2755abe338fSAMS21 return DefaultableMemberKind::CompareRelational;
2765abe338fSAMS21
2775abe338fSAMS21 default:
2785abe338fSAMS21 break;
2795abe338fSAMS21 }
2805abe338fSAMS21
2815abe338fSAMS21 // Not a defaultable member kind
2825abe338fSAMS21 return DefaultableMemberKind::None;
2835abe338fSAMS21 }
2845abe338fSAMS21
2855abe338fSAMS21 } // namespace clang::tidy::utils
286