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