1 //===--- UseUncaughtExceptionsCheck.cpp - clang-tidy--------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "UseUncaughtExceptionsCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang { 16 namespace tidy { 17 namespace modernize { 18 19 void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) { 20 if (!getLangOpts().CPlusPlus17) 21 return; 22 23 std::string MatchText = "::std::uncaught_exception"; 24 25 // Using declaration: warning and fix-it. 26 Finder->addMatcher( 27 usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(hasName(MatchText)))) 28 .bind("using_decl"), 29 this); 30 31 // DeclRefExpr: warning, no fix-it. 32 Finder->addMatcher( 33 declRefExpr(to(functionDecl(hasName(MatchText))), unless(callExpr())) 34 .bind("decl_ref_expr"), 35 this); 36 37 auto DirectCallToUncaughtException = callee(expr(ignoringImpCasts( 38 declRefExpr(hasDeclaration(functionDecl(hasName(MatchText))))))); 39 40 // CallExpr: warning, fix-it. 41 Finder->addMatcher(callExpr(DirectCallToUncaughtException, 42 unless(hasAncestor(initListExpr()))) 43 .bind("call_expr"), 44 this); 45 // CallExpr in initialisation list: warning, fix-it with avoiding narrowing 46 // conversions. 47 Finder->addMatcher(callExpr(DirectCallToUncaughtException, 48 hasAncestor(initListExpr())) 49 .bind("init_call_expr"), 50 this); 51 } 52 53 void UseUncaughtExceptionsCheck::check(const MatchFinder::MatchResult &Result) { 54 SourceLocation BeginLoc; 55 SourceLocation EndLoc; 56 const CallExpr *C = Result.Nodes.getNodeAs<CallExpr>("init_call_expr"); 57 bool WarnOnly = false; 58 59 if (C) { 60 BeginLoc = C->getBeginLoc(); 61 EndLoc = C->getEndLoc(); 62 } else if (const auto *E = Result.Nodes.getNodeAs<CallExpr>("call_expr")) { 63 BeginLoc = E->getBeginLoc(); 64 EndLoc = E->getEndLoc(); 65 } else if (const auto *D = 66 Result.Nodes.getNodeAs<DeclRefExpr>("decl_ref_expr")) { 67 BeginLoc = D->getBeginLoc(); 68 EndLoc = D->getEndLoc(); 69 WarnOnly = true; 70 } else { 71 const auto *U = Result.Nodes.getNodeAs<UsingDecl>("using_decl"); 72 assert(U && "Null pointer, no node provided"); 73 BeginLoc = U->getNameInfo().getBeginLoc(); 74 EndLoc = U->getNameInfo().getEndLoc(); 75 } 76 77 auto Diag = diag(BeginLoc, "'std::uncaught_exception' is deprecated, use " 78 "'std::uncaught_exceptions' instead"); 79 80 if (!BeginLoc.isMacroID()) { 81 StringRef Text = 82 Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc), 83 *Result.SourceManager, getLangOpts()); 84 85 Text.consume_back("()"); 86 int TextLength = Text.size(); 87 88 if (WarnOnly) { 89 return; 90 } 91 92 if (!C) { 93 Diag << FixItHint::CreateInsertion(BeginLoc.getLocWithOffset(TextLength), 94 "s"); 95 } else { 96 Diag << FixItHint::CreateReplacement(C->getSourceRange(), 97 "std::uncaught_exceptions() > 0"); 98 } 99 } 100 } 101 102 } // namespace modernize 103 } // namespace tidy 104 } // namespace clang 105