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   // CallExpr: warning, fix-it.
38   Finder->addMatcher(callExpr(hasDeclaration(functionDecl(hasName(MatchText))),
39                               unless(hasAncestor(initListExpr())))
40                          .bind("call_expr"),
41                      this);
42   // CallExpr in initialisation list: warning, fix-it with avoiding narrowing
43   // conversions.
44   Finder->addMatcher(callExpr(hasAncestor(initListExpr()),
45                               hasDeclaration(functionDecl(hasName(MatchText))))
46                          .bind("init_call_expr"),
47                      this);
48 }
49 
50 void UseUncaughtExceptionsCheck::check(const MatchFinder::MatchResult &Result) {
51   SourceLocation BeginLoc;
52   SourceLocation EndLoc;
53   const CallExpr *C = Result.Nodes.getNodeAs<CallExpr>("init_call_expr");
54   bool WarnOnly = false;
55 
56   if (C) {
57     BeginLoc = C->getBeginLoc();
58     EndLoc = C->getEndLoc();
59   } else if (const auto *E = Result.Nodes.getNodeAs<CallExpr>("call_expr")) {
60     BeginLoc = E->getBeginLoc();
61     EndLoc = E->getEndLoc();
62   } else if (const auto *D =
63                  Result.Nodes.getNodeAs<DeclRefExpr>("decl_ref_expr")) {
64     BeginLoc = D->getBeginLoc();
65     EndLoc = D->getEndLoc();
66     WarnOnly = true;
67   } else {
68     const auto *U = Result.Nodes.getNodeAs<UsingDecl>("using_decl");
69     assert(U && "Null pointer, no node provided");
70     BeginLoc = U->getNameInfo().getBeginLoc();
71     EndLoc = U->getNameInfo().getEndLoc();
72   }
73 
74   auto Diag = diag(BeginLoc, "'std::uncaught_exception' is deprecated, use "
75                              "'std::uncaught_exceptions' instead");
76 
77   if (!BeginLoc.isMacroID()) {
78     StringRef Text =
79         Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
80                              *Result.SourceManager, getLangOpts());
81 
82     Text.consume_back("()");
83     int TextLength = Text.size();
84 
85     if (WarnOnly) {
86       return;
87     }
88 
89     if (!C) {
90       Diag << FixItHint::CreateInsertion(BeginLoc.getLocWithOffset(TextLength),
91                                          "s");
92     } else {
93       Diag << FixItHint::CreateReplacement(C->getSourceRange(),
94                                            "std::uncaught_exceptions() > 0");
95     }
96   }
97 }
98 
99 } // namespace modernize
100 } // namespace tidy
101 } // namespace clang
102