1 //===--- UseNoexceptCheck.cpp - clang-tidy---------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "UseNoexceptCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/Lex/Lexer.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace modernize { 19 20 UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context) 21 : ClangTidyCheck(Name, Context), 22 NoexceptMacro(Options.get("ReplacementString", "")), 23 UseNoexceptFalse(Options.get("UseNoexceptFalse", true)) {} 24 25 void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { 26 Options.store(Opts, "ReplacementString", NoexceptMacro); 27 Options.store(Opts, "UseNoexceptFalse", UseNoexceptFalse); 28 } 29 30 void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) { 31 if (!getLangOpts().CPlusPlus11) 32 return; 33 34 Finder->addMatcher( 35 functionDecl( 36 cxxMethodDecl( 37 hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))), 38 anyOf(hasOverloadedOperatorName("delete[]"), 39 hasOverloadedOperatorName("delete"), cxxDestructorDecl())) 40 .bind("del-dtor")) 41 .bind("funcDecl"), 42 this); 43 44 Finder->addMatcher( 45 functionDecl( 46 hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))), 47 unless(anyOf(hasOverloadedOperatorName("delete[]"), 48 hasOverloadedOperatorName("delete"), 49 cxxDestructorDecl()))) 50 .bind("funcDecl"), 51 this); 52 53 Finder->addMatcher( 54 parmVarDecl(anyOf(hasType(pointerType(pointee(parenType(innerType( 55 functionProtoType(hasDynamicExceptionSpec())))))), 56 hasType(memberPointerType(pointee(parenType(innerType( 57 functionProtoType(hasDynamicExceptionSpec())))))))) 58 .bind("parmVarDecl"), 59 this); 60 } 61 62 void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) { 63 const FunctionProtoType *FnTy = nullptr; 64 bool DtorOrOperatorDel = false; 65 SourceRange Range; 66 67 if (const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl")) { 68 DtorOrOperatorDel = Result.Nodes.getNodeAs<FunctionDecl>("del-dtor"); 69 FnTy = FuncDecl->getType()->getAs<FunctionProtoType>(); 70 if (const auto *TSI = FuncDecl->getTypeSourceInfo()) 71 Range = 72 TSI->getTypeLoc().castAs<FunctionTypeLoc>().getExceptionSpecRange(); 73 } else if (const auto *ParmDecl = 74 Result.Nodes.getNodeAs<ParmVarDecl>("parmVarDecl")) { 75 FnTy = ParmDecl->getType() 76 ->getAs<Type>() 77 ->getPointeeType() 78 ->getAs<FunctionProtoType>(); 79 80 if (const auto *TSI = ParmDecl->getTypeSourceInfo()) 81 Range = TSI->getTypeLoc() 82 .getNextTypeLoc() 83 .IgnoreParens() 84 .castAs<FunctionProtoTypeLoc>() 85 .getExceptionSpecRange(); 86 } 87 CharSourceRange CRange = Lexer::makeFileCharRange( 88 CharSourceRange::getTokenRange(Range), *Result.SourceManager, 89 Result.Context->getLangOpts()); 90 91 assert(FnTy && "FunctionProtoType is null."); 92 bool IsNoThrow = FnTy->isNothrow(*Result.Context); 93 StringRef ReplacementStr = 94 IsNoThrow 95 ? NoexceptMacro.empty() ? "noexcept" : NoexceptMacro.c_str() 96 : NoexceptMacro.empty() 97 ? (DtorOrOperatorDel || UseNoexceptFalse) ? "noexcept(false)" 98 : "" 99 : ""; 100 101 FixItHint FixIt; 102 if ((IsNoThrow || NoexceptMacro.empty()) && CRange.isValid()) 103 FixIt = FixItHint::CreateReplacement(CRange, ReplacementStr); 104 105 diag(Range.getBegin(), "dynamic exception specification '%0' is deprecated; " 106 "consider %select{using '%2'|removing it}1 instead") 107 << Lexer::getSourceText(CRange, *Result.SourceManager, 108 Result.Context->getLangOpts()) 109 << ReplacementStr.empty() << ReplacementStr << FixIt; 110 } 111 112 } // namespace modernize 113 } // namespace tidy 114 } // namespace clang 115