1 //===--- UseNoexceptCheck.cpp - clang-tidy---------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "UseNoexceptCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/Lex/Lexer.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::modernize
{
18 AST_MATCHER(NamedDecl
, isValid
) { return !Node
.isInvalidDecl(); }
21 UseNoexceptCheck::UseNoexceptCheck(StringRef Name
, ClangTidyContext
*Context
)
22 : ClangTidyCheck(Name
, Context
),
23 NoexceptMacro(Options
.get("ReplacementString", "")),
24 UseNoexceptFalse(Options
.get("UseNoexceptFalse", true)) {}
26 void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
27 Options
.store(Opts
, "ReplacementString", NoexceptMacro
);
28 Options
.store(Opts
, "UseNoexceptFalse", UseNoexceptFalse
);
31 void UseNoexceptCheck::registerMatchers(MatchFinder
*Finder
) {
35 hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))),
36 optionally(cxxMethodDecl(anyOf(hasAnyOverloadedOperatorName(
37 "delete[]", "delete"),
44 parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType(
45 functionProtoType(hasDynamicExceptionSpec())))))),
46 hasType(memberPointerType(pointee(parenType(innerType(
47 functionProtoType(hasDynamicExceptionSpec()))))))))
52 void UseNoexceptCheck::check(const MatchFinder::MatchResult
&Result
) {
53 const FunctionProtoType
*FnTy
= nullptr;
54 bool DtorOrOperatorDel
= false;
57 if (const auto *FuncDecl
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("funcDecl")) {
58 DtorOrOperatorDel
= Result
.Nodes
.getNodeAs
<FunctionDecl
>("del-dtor");
59 FnTy
= FuncDecl
->getType()->getAs
<FunctionProtoType
>();
60 if (const auto *TSI
= FuncDecl
->getTypeSourceInfo())
62 TSI
->getTypeLoc().castAs
<FunctionTypeLoc
>().getExceptionSpecRange();
63 } else if (const auto *ParmDecl
=
64 Result
.Nodes
.getNodeAs
<ParmVarDecl
>("parmVarDecl")) {
65 FnTy
= ParmDecl
->getType()
68 ->getAs
<FunctionProtoType
>();
70 if (const auto *TSI
= ParmDecl
->getTypeSourceInfo())
71 Range
= TSI
->getTypeLoc()
74 .castAs
<FunctionProtoTypeLoc
>()
75 .getExceptionSpecRange();
78 assert(FnTy
&& "FunctionProtoType is null.");
79 if (isUnresolvedExceptionSpec(FnTy
->getExceptionSpecType()))
82 assert(Range
.isValid() && "Exception Source Range is invalid.");
84 CharSourceRange CRange
= Lexer::makeFileCharRange(
85 CharSourceRange::getTokenRange(Range
), *Result
.SourceManager
,
86 Result
.Context
->getLangOpts());
88 bool IsNoThrow
= FnTy
->isNothrow();
89 StringRef ReplacementStr
=
90 IsNoThrow
? NoexceptMacro
.empty() ? "noexcept" : NoexceptMacro
91 : NoexceptMacro
.empty()
92 ? (DtorOrOperatorDel
|| UseNoexceptFalse
) ? "noexcept(false)" : ""
96 if ((IsNoThrow
|| NoexceptMacro
.empty()) && CRange
.isValid())
97 FixIt
= FixItHint::CreateReplacement(CRange
, ReplacementStr
);
99 diag(Range
.getBegin(), "dynamic exception specification '%0' is deprecated; "
100 "consider %select{using '%2'|removing it}1 instead")
101 << Lexer::getSourceText(CRange
, *Result
.SourceManager
,
102 Result
.Context
->getLangOpts())
103 << ReplacementStr
.empty() << ReplacementStr
<< FixIt
;
106 } // namespace clang::tidy::modernize