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