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