xref: /llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp (revision da3dc0011e06c9f1aebe71d76eae92dc76e3db2e)
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