xref: /llvm-project/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp (revision 7d2ea6c422d3f5712b7253407005e1a465a76946)
108936e47SAlexander Kornienko //===--- UseNoexceptCheck.cpp - clang-tidy---------------------------------===//
208936e47SAlexander Kornienko //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
608936e47SAlexander Kornienko //
708936e47SAlexander Kornienko //===----------------------------------------------------------------------===//
808936e47SAlexander Kornienko 
908936e47SAlexander Kornienko #include "UseNoexceptCheck.h"
1008936e47SAlexander Kornienko #include "clang/AST/ASTContext.h"
1108936e47SAlexander Kornienko #include "clang/Lex/Lexer.h"
1208936e47SAlexander Kornienko 
1308936e47SAlexander Kornienko using namespace clang::ast_matchers;
1408936e47SAlexander Kornienko 
15*7d2ea6c4SCarlos Galvez namespace clang::tidy::modernize {
1608936e47SAlexander Kornienko 
174c5818ddSNathan James namespace {
AST_MATCHER(NamedDecl,isValid)184c5818ddSNathan James AST_MATCHER(NamedDecl, isValid) { return !Node.isInvalidDecl(); }
194c5818ddSNathan James } // namespace
204c5818ddSNathan James 
UseNoexceptCheck(StringRef Name,ClangTidyContext * Context)2108936e47SAlexander Kornienko UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context)
2208936e47SAlexander Kornienko     : ClangTidyCheck(Name, Context),
2308936e47SAlexander Kornienko       NoexceptMacro(Options.get("ReplacementString", "")),
2408936e47SAlexander Kornienko       UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {}
2508936e47SAlexander Kornienko 
storeOptions(ClangTidyOptions::OptionMap & Opts)2608936e47SAlexander Kornienko void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
2708936e47SAlexander Kornienko   Options.store(Opts, "ReplacementString", NoexceptMacro);
2808936e47SAlexander Kornienko   Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse);
2908936e47SAlexander Kornienko }
3008936e47SAlexander Kornienko 
registerMatchers(MatchFinder * Finder)3108936e47SAlexander Kornienko void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) {
3208936e47SAlexander Kornienko   Finder->addMatcher(
3308936e47SAlexander Kornienko       functionDecl(
344c5818ddSNathan James           isValid(),
3508936e47SAlexander Kornienko           hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))),
364c5818ddSNathan James           optionally(cxxMethodDecl(anyOf(hasAnyOverloadedOperatorName(
374c5818ddSNathan James                                              "delete[]", "delete"),
384c5818ddSNathan James                                          cxxDestructorDecl()))
394c5818ddSNathan James                          .bind("del-dtor")))
4008936e47SAlexander Kornienko           .bind("funcDecl"),
4108936e47SAlexander Kornienko       this);
4208936e47SAlexander Kornienko 
4308936e47SAlexander Kornienko   Finder->addMatcher(
4408936e47SAlexander Kornienko       parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType(
4508936e47SAlexander Kornienko                             functionProtoType(hasDynamicExceptionSpec())))))),
4608936e47SAlexander Kornienko                         hasType(memberPointerType(pointee(parenType(innerType(
4708936e47SAlexander Kornienko                             functionProtoType(hasDynamicExceptionSpec()))))))))
4808936e47SAlexander Kornienko           .bind("parmVarDecl"),
4908936e47SAlexander Kornienko       this);
5008936e47SAlexander Kornienko }
5108936e47SAlexander Kornienko 
check(const MatchFinder::MatchResult & Result)5208936e47SAlexander Kornienko void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) {
5308936e47SAlexander Kornienko   const FunctionProtoType *FnTy = nullptr;
5408936e47SAlexander Kornienko   bool DtorOrOperatorDel = false;
5508936e47SAlexander Kornienko   SourceRange Range;
5608936e47SAlexander Kornienko 
5708936e47SAlexander Kornienko   if (const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) {
5808936e47SAlexander Kornienko     DtorOrOperatorDel = Result.Nodes.getNodeAs<FunctionDecl>("del-dtor");
5908936e47SAlexander Kornienko     FnTy = FuncDecl->getType()->getAs<FunctionProtoType>();
6008936e47SAlexander Kornienko     if (const auto *TSI = FuncDecl->getTypeSourceInfo())
6108936e47SAlexander Kornienko       Range =
6208936e47SAlexander Kornienko           TSI->getTypeLoc().castAs<FunctionTypeLoc>().getExceptionSpecRange();
6308936e47SAlexander Kornienko   } else if (const auto *ParmDecl =
6408936e47SAlexander Kornienko                  Result.Nodes.getNodeAs<ParmVarDecl>("parmVarDecl")) {
6508936e47SAlexander Kornienko     FnTy = ParmDecl->getType()
6699acc0dcSSimon Pilgrim                ->castAs<Type>()
6708936e47SAlexander Kornienko                ->getPointeeType()
6808936e47SAlexander Kornienko                ->getAs<FunctionProtoType>();
6908936e47SAlexander Kornienko 
7008936e47SAlexander Kornienko     if (const auto *TSI = ParmDecl->getTypeSourceInfo())
7108936e47SAlexander Kornienko       Range = TSI->getTypeLoc()
7208936e47SAlexander Kornienko                   .getNextTypeLoc()
7308936e47SAlexander Kornienko                   .IgnoreParens()
7408936e47SAlexander Kornienko                   .castAs<FunctionProtoTypeLoc>()
7508936e47SAlexander Kornienko                   .getExceptionSpecRange();
7608936e47SAlexander Kornienko   }
774c5818ddSNathan James 
7896c6d012SZinovy Nis   assert(FnTy && "FunctionProtoType is null.");
7996c6d012SZinovy Nis   if (isUnresolvedExceptionSpec(FnTy->getExceptionSpecType()))
8096c6d012SZinovy Nis     return;
8196c6d012SZinovy Nis 
824c5818ddSNathan James   assert(Range.isValid() && "Exception Source Range is invalid.");
834c5818ddSNathan James 
8408936e47SAlexander Kornienko   CharSourceRange CRange = Lexer::makeFileCharRange(
8508936e47SAlexander Kornienko       CharSourceRange::getTokenRange(Range), *Result.SourceManager,
8608936e47SAlexander Kornienko       Result.Context->getLangOpts());
8708936e47SAlexander Kornienko 
88800508b8SRichard Smith   bool IsNoThrow = FnTy->isNothrow();
8908936e47SAlexander Kornienko   StringRef ReplacementStr =
9012cb5405SNathan James       IsNoThrow ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro
9108936e47SAlexander Kornienko       : NoexceptMacro.empty()
9212cb5405SNathan James           ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)" : ""
9308936e47SAlexander Kornienko           : "";
9408936e47SAlexander Kornienko 
9508936e47SAlexander Kornienko   FixItHint FixIt;
9608936e47SAlexander Kornienko   if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid())
9708936e47SAlexander Kornienko     FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr);
9808936e47SAlexander Kornienko 
9908936e47SAlexander Kornienko   diag(Range.getBegin(), "dynamic exception specification '%0' is deprecated; "
10008936e47SAlexander Kornienko                          "consider %select{using '%2'|removing it}1 instead")
10108936e47SAlexander Kornienko       << Lexer::getSourceText(CRange, *Result.SourceManager,
10208936e47SAlexander Kornienko                               Result.Context->getLangOpts())
10308936e47SAlexander Kornienko       << ReplacementStr.empty() << ReplacementStr << FixIt;
10408936e47SAlexander Kornienko }
10508936e47SAlexander Kornienko 
106*7d2ea6c4SCarlos Galvez } // namespace clang::tidy::modernize
107