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 | |
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 | NodeMatch: usingDecl(hasAnyUsingShadowDecl(InnerMatcher: hasTargetDecl(InnerMatcher: hasName(Name: MatchText)))) |
24 | .bind(ID: "using_decl" ), |
25 | Action: this); |
26 | |
27 | // DeclRefExpr: warning, no fix-it. |
28 | Finder->addMatcher( |
29 | NodeMatch: declRefExpr(to(InnerMatcher: functionDecl(hasName(Name: MatchText))), unless(callExpr())) |
30 | .bind(ID: "decl_ref_expr" ), |
31 | Action: this); |
32 | |
33 | auto DirectCallToUncaughtException = callee(InnerMatcher: expr(ignoringImpCasts( |
34 | InnerMatcher: declRefExpr(hasDeclaration(InnerMatcher: functionDecl(hasName(Name: MatchText))))))); |
35 | |
36 | // CallExpr: warning, fix-it. |
37 | Finder->addMatcher(NodeMatch: callExpr(DirectCallToUncaughtException, |
38 | unless(hasAncestor(initListExpr()))) |
39 | .bind(ID: "call_expr" ), |
40 | Action: this); |
41 | // CallExpr in initialisation list: warning, fix-it with avoiding narrowing |
42 | // conversions. |
43 | Finder->addMatcher(NodeMatch: callExpr(DirectCallToUncaughtException, |
44 | hasAncestor(initListExpr())) |
45 | .bind(ID: "init_call_expr" ), |
46 | Action: this); |
47 | } |
48 | |
49 | void UseUncaughtExceptionsCheck::check(const MatchFinder::MatchResult &Result) { |
50 | SourceLocation BeginLoc; |
51 | SourceLocation EndLoc; |
52 | const auto *C = Result.Nodes.getNodeAs<CallExpr>(ID: "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>(ID: "call_expr" )) { |
59 | BeginLoc = E->getBeginLoc(); |
60 | EndLoc = E->getEndLoc(); |
61 | } else if (const auto *D = |
62 | Result.Nodes.getNodeAs<DeclRefExpr>(ID: "decl_ref_expr" )) { |
63 | BeginLoc = D->getBeginLoc(); |
64 | EndLoc = D->getEndLoc(); |
65 | WarnOnly = true; |
66 | } else { |
67 | const auto *U = Result.Nodes.getNodeAs<UsingDecl>(ID: "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(Loc: BeginLoc, Description: "'std::uncaught_exception' is deprecated, use " |
74 | "'std::uncaught_exceptions' instead" ); |
75 | |
76 | if (!BeginLoc.isMacroID()) { |
77 | StringRef Text = |
78 | Lexer::getSourceText(Range: CharSourceRange::getTokenRange(B: BeginLoc, E: EndLoc), |
79 | SM: *Result.SourceManager, LangOpts: getLangOpts()); |
80 | |
81 | Text.consume_back(Suffix: "()" ); |
82 | int TextLength = Text.size(); |
83 | |
84 | if (WarnOnly) { |
85 | return; |
86 | } |
87 | |
88 | if (!C) { |
89 | Diag << FixItHint::CreateInsertion(InsertionLoc: BeginLoc.getLocWithOffset(Offset: TextLength), |
90 | Code: "s" ); |
91 | } else { |
92 | Diag << FixItHint::CreateReplacement(C->getSourceRange(), |
93 | "std::uncaught_exceptions() > 0" ); |
94 | } |
95 | } |
96 | } |
97 | |
98 | } // namespace clang::tidy::modernize |
99 | |