diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp new file mode 100644 index 00000000000..a38274ebbd2 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp @@ -0,0 +1,114 @@ +//===--- UseNoexceptCheck.cpp - clang-tidy---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UseNoexceptCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + NoexceptMacro(Options.get("ReplacementString", "")), + UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {} + +void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "ReplacementString", NoexceptMacro); + Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse); +} + +void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + + Finder->addMatcher( + functionDecl( + cxxMethodDecl( + hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))), + anyOf(hasOverloadedOperatorName("delete[]"), + hasOverloadedOperatorName("delete"), cxxDestructorDecl())) + .bind("del-dtor")) + .bind("funcDecl"), + this); + + Finder->addMatcher( + functionDecl( + hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))), + unless(anyOf(hasOverloadedOperatorName("delete[]"), + hasOverloadedOperatorName("delete"), + cxxDestructorDecl()))) + .bind("funcDecl"), + this); + + Finder->addMatcher( + parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType( + functionProtoType(hasDynamicExceptionSpec())))))), + hasType(memberPointerType(pointee(parenType(innerType( + functionProtoType(hasDynamicExceptionSpec())))))))) + .bind("parmVarDecl"), + this); +} + +void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) { + const FunctionProtoType *FnTy = nullptr; + bool DtorOrOperatorDel = false; + SourceRange Range; + + if (const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) { + DtorOrOperatorDel = Result.Nodes.getNodeAs<FunctionDecl>("del-dtor"); + FnTy = FuncDecl->getType()->getAs<FunctionProtoType>(); + if (const auto *TSI = FuncDecl->getTypeSourceInfo()) + Range = + TSI->getTypeLoc().castAs<FunctionTypeLoc>().getExceptionSpecRange(); + } else if (const auto *ParmDecl = + Result.Nodes.getNodeAs<ParmVarDecl>("parmVarDecl")) { + FnTy = ParmDecl->getType() + ->getAs<Type>() + ->getPointeeType() + ->getAs<FunctionProtoType>(); + + if (const auto *TSI = ParmDecl->getTypeSourceInfo()) + Range = TSI->getTypeLoc() + .getNextTypeLoc() + .IgnoreParens() + .castAs<FunctionProtoTypeLoc>() + .getExceptionSpecRange(); + } + CharSourceRange CRange = Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(Range), *Result.SourceManager, + Result.Context->getLangOpts()); + + assert(FnTy && "FunctionProtoType is null."); + bool IsNoThrow = FnTy->isNothrow(*Result.Context); + StringRef ReplacementStr = + IsNoThrow + ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro + : NoexceptMacro.empty() + ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)" + : "" + : ""; + + FixItHint FixIt; + if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid()) + FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr); + + diag(Range.getBegin(), "dynamic exception specification '%0' is deprecated; " + "consider %select{using '%2'|removing it}1 instead") + << Lexer::getSourceText(CRange, *Result.SourceManager, + Result.Context->getLangOpts()) + << ReplacementStr.empty() << ReplacementStr << FixIt; +} + +} // namespace modernize +} // namespace tidy +} // namespace clang |