//===--- 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("funcDecl")) { DtorOrOperatorDel = Result.Nodes.getNodeAs("del-dtor"); FnTy = FuncDecl->getType()->getAs(); if (const auto *TSI = FuncDecl->getTypeSourceInfo()) Range = TSI->getTypeLoc().castAs().getExceptionSpecRange(); } else if (const auto *ParmDecl = Result.Nodes.getNodeAs("parmVarDecl")) { FnTy = ParmDecl->getType() ->getAs() ->getPointeeType() ->getAs(); if (const auto *TSI = ParmDecl->getTypeSourceInfo()) Range = TSI->getTypeLoc() .getNextTypeLoc() .IgnoreParens() .castAs() .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