| //===--- 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(); |
| StringRef ReplacementStr = |
| IsNoThrow |
| ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro.c_str() |
| : 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 |