llvm-project/clang-tools-extra/clang-tidy/modernize/UseUncaughtExceptionsCheck.cpp

103 lines
3.4 KiB
C++

//===--- UseUncaughtExceptionsCheck.cpp - clang-tidy--------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "UseUncaughtExceptionsCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
namespace clang {
namespace tidy {
namespace modernize {
void UseUncaughtExceptionsCheck::registerMatchers(MatchFinder *Finder) {
std::string MatchText = "::std::uncaught_exception";
// Using declaration: warning and fix-it.
Finder->addMatcher(
usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(hasName(MatchText))))
.bind("using_decl"),
this);
// DeclRefExpr: warning, no fix-it.
Finder->addMatcher(
declRefExpr(to(functionDecl(hasName(MatchText))), unless(callExpr()))
.bind("decl_ref_expr"),
this);
auto DirectCallToUncaughtException = callee(expr(ignoringImpCasts(
declRefExpr(hasDeclaration(functionDecl(hasName(MatchText)))))));
// CallExpr: warning, fix-it.
Finder->addMatcher(callExpr(DirectCallToUncaughtException,
unless(hasAncestor(initListExpr())))
.bind("call_expr"),
this);
// CallExpr in initialisation list: warning, fix-it with avoiding narrowing
// conversions.
Finder->addMatcher(callExpr(DirectCallToUncaughtException,
hasAncestor(initListExpr()))
.bind("init_call_expr"),
this);
}
void UseUncaughtExceptionsCheck::check(const MatchFinder::MatchResult &Result) {
SourceLocation BeginLoc;
SourceLocation EndLoc;
const CallExpr *C = Result.Nodes.getNodeAs<CallExpr>("init_call_expr");
bool WarnOnly = false;
if (C) {
BeginLoc = C->getBeginLoc();
EndLoc = C->getEndLoc();
} else if (const auto *E = Result.Nodes.getNodeAs<CallExpr>("call_expr")) {
BeginLoc = E->getBeginLoc();
EndLoc = E->getEndLoc();
} else if (const auto *D =
Result.Nodes.getNodeAs<DeclRefExpr>("decl_ref_expr")) {
BeginLoc = D->getBeginLoc();
EndLoc = D->getEndLoc();
WarnOnly = true;
} else {
const auto *U = Result.Nodes.getNodeAs<UsingDecl>("using_decl");
assert(U && "Null pointer, no node provided");
BeginLoc = U->getNameInfo().getBeginLoc();
EndLoc = U->getNameInfo().getEndLoc();
}
auto Diag = diag(BeginLoc, "'std::uncaught_exception' is deprecated, use "
"'std::uncaught_exceptions' instead");
if (!BeginLoc.isMacroID()) {
StringRef Text =
Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
*Result.SourceManager, getLangOpts());
Text.consume_back("()");
int TextLength = Text.size();
if (WarnOnly) {
return;
}
if (!C) {
Diag << FixItHint::CreateInsertion(BeginLoc.getLocWithOffset(TextLength),
"s");
} else {
Diag << FixItHint::CreateReplacement(C->getSourceRange(),
"std::uncaught_exceptions() > 0");
}
}
}
} // namespace modernize
} // namespace tidy
} // namespace clang