diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -5,6 +5,7 @@ add_clang_library(clangTidyPerformanceModule AvoidEndlCheck.cpp + BaseNoexceptFunctionCheck.cpp FasterStringFindCheck.cpp ForRangeCopyCheck.cpp ImplicitConversionInLoopCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h --- a/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h +++ b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTDESTRUCTORCHECK_H #include "../ClangTidyCheck.h" -#include "../utils/ExceptionSpecAnalyzer.h" +#include "BaseNoexceptFunctionCheck.h" namespace clang::tidy::performance { @@ -20,21 +20,17 @@ /// /// For the user-facing documentation see: /// https://clang.llvm.org/extra/clang-tidy/checks/performance/noexcept-destructor.html -class NoexceptDestructorCheck : public ClangTidyCheck { +class NoexceptDestructorCheck : public BaseNoexceptFunctionCheck { public: - NoexceptDestructorCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + using BaseNoexceptFunctionCheck::BaseNoexceptFunctionCheck; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; - bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions; - } - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - std::optional getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; - } - -private: - utils::ExceptionSpecAnalyzer SpecAnalyzer; + +protected: + DiagnosticBuilder + reportMissingNoexcept(const FunctionDecl *FuncDecl) final override; + void reportNoexceptEvaluatedToFalse(const FunctionDecl *FuncDecl, + const Expr *NoexceptExpr) final override; }; } // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// #include "NoexceptDestructorCheck.h" -#include "../utils/LexerUtils.h" -#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; @@ -16,42 +14,21 @@ namespace clang::tidy::performance { void NoexceptDestructorCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher( - functionDecl(unless(isDeleted()), cxxDestructorDecl()).bind("decl"), - this); + Finder->addMatcher(functionDecl(unless(isDeleted()), cxxDestructorDecl()) + .bind(BindFuncDeclName), + this); } -void NoexceptDestructorCheck::check(const MatchFinder::MatchResult &Result) { - const auto *FuncDecl = Result.Nodes.getNodeAs("decl"); - assert(FuncDecl); - - if (SpecAnalyzer.analyze(FuncDecl) != - utils::ExceptionSpecAnalyzer::State::Throwing) - return; - - // Don't complain about nothrow(false), but complain on nothrow(expr) - // where expr evaluates to false. - const auto *ProtoType = FuncDecl->getType()->castAs(); - const Expr *NoexceptExpr = ProtoType->getNoexceptExpr(); - if (NoexceptExpr) { - NoexceptExpr = NoexceptExpr->IgnoreImplicit(); - if (!isa(NoexceptExpr)) { - diag(NoexceptExpr->getExprLoc(), - "noexcept specifier on the destructor evaluates to 'false'"); - } - return; - } - - auto Diag = diag(FuncDecl->getLocation(), "destructors should " - "be marked noexcept"); - - // Add FixIt hints. - const SourceManager &SM = *Result.SourceManager; +DiagnosticBuilder +NoexceptDestructorCheck::reportMissingNoexcept(const FunctionDecl *FuncDecl) { + return diag(FuncDecl->getLocation(), "destructors should " + "be marked noexcept"); +} - const SourceLocation NoexceptLoc = - utils::lexer::getLocationForNoexceptSpecifier(FuncDecl, SM); - if (NoexceptLoc.isValid()) - Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); +void NoexceptDestructorCheck::reportNoexceptEvaluatedToFalse( + const FunctionDecl *FuncDecl, const Expr *NoexceptExpr) { + diag(NoexceptExpr->getExprLoc(), + "noexcept specifier on the destructor evaluates to 'false'"); } } // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h --- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h +++ b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H #include "../ClangTidyCheck.h" -#include "../utils/ExceptionSpecAnalyzer.h" +#include "BaseNoexceptFunctionCheck.h" namespace clang::tidy::performance { @@ -24,21 +24,17 @@ /// /// For the user-facing documentation see: /// https://clang.llvm.org/extra/clang-tidy/checks/performance/noexcept-move-constructor.html -class NoexceptMoveConstructorCheck : public ClangTidyCheck { +class NoexceptMoveConstructorCheck : public BaseNoexceptFunctionCheck { public: - NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} - bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions; - } + using BaseNoexceptFunctionCheck::BaseNoexceptFunctionCheck; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - std::optional getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; - } -private: - utils::ExceptionSpecAnalyzer SpecAnalyzer; +protected: + DiagnosticBuilder + reportMissingNoexcept(const FunctionDecl *FuncDecl) final override; + void reportNoexceptEvaluatedToFalse(const FunctionDecl *FuncDecl, + const Expr *NoexceptExpr) final override; }; } // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp @@ -7,11 +7,7 @@ //===----------------------------------------------------------------------===// #include "NoexceptMoveConstructorCheck.h" -#include "../utils/LexerUtils.h" -#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" -#include "clang/Tooling/FixIt.h" using namespace clang::ast_matchers; @@ -22,48 +18,24 @@ cxxMethodDecl(unless(isDeleted()), anyOf(cxxConstructorDecl(isMoveConstructor()), isMoveAssignmentOperator())) - .bind("decl"), + .bind(BindFuncDeclName), this); } -void NoexceptMoveConstructorCheck::check( - const MatchFinder::MatchResult &Result) { - const auto *FuncDecl = Result.Nodes.getNodeAs("decl"); - assert(FuncDecl); - - if (SpecAnalyzer.analyze(FuncDecl) != - utils::ExceptionSpecAnalyzer::State::Throwing) - return; - - const bool IsConstructor = CXXConstructorDecl::classof(FuncDecl); - - // Don't complain about nothrow(false), but complain on nothrow(expr) - // where expr evaluates to false. - const auto *ProtoType = FuncDecl->getType()->castAs(); - const Expr *NoexceptExpr = ProtoType->getNoexceptExpr(); - if (NoexceptExpr) { - NoexceptExpr = NoexceptExpr->IgnoreImplicit(); - if (!isa(NoexceptExpr)) { - diag(NoexceptExpr->getExprLoc(), - "noexcept specifier on the move %select{assignment " - "operator|constructor}0 evaluates to 'false'") - << IsConstructor; - } - return; - } - - auto Diag = diag(FuncDecl->getLocation(), - "move %select{assignment operator|constructor}0s should " - "be marked noexcept") - << IsConstructor; - // Add FixIt hints. - - const SourceManager &SM = *Result.SourceManager; +DiagnosticBuilder NoexceptMoveConstructorCheck::reportMissingNoexcept( + const FunctionDecl *FuncDecl) { + return diag(FuncDecl->getLocation(), + "move %select{assignment operator|constructor}0s should " + "be marked noexcept") + << CXXConstructorDecl::classof(FuncDecl); +} - const SourceLocation NoexceptLoc = - utils::lexer::getLocationForNoexceptSpecifier(FuncDecl, SM); - if (NoexceptLoc.isValid()) - Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); +void NoexceptMoveConstructorCheck::reportNoexceptEvaluatedToFalse( + const FunctionDecl *FuncDecl, const Expr *NoexceptExpr) { + diag(NoexceptExpr->getExprLoc(), + "noexcept specifier on the move %select{assignment " + "operator|constructor}0 evaluates to 'false'") + << CXXConstructorDecl::classof(FuncDecl); } } // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h --- a/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h +++ b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h @@ -10,7 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSWAPCHECK_H #include "../ClangTidyCheck.h" -#include "../utils/ExceptionSpecAnalyzer.h" +#include "BaseNoexceptFunctionCheck.h" namespace clang::tidy::performance { @@ -20,21 +20,17 @@ /// /// For the user-facing documentation see: /// https://clang.llvm.org/extra/clang-tidy/checks/performance/noexcept-swap.html -class NoexceptSwapCheck : public ClangTidyCheck { +class NoexceptSwapCheck : public BaseNoexceptFunctionCheck { public: - NoexceptSwapCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + using BaseNoexceptFunctionCheck::BaseNoexceptFunctionCheck; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; - bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions; - } - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - std::optional getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; - } - -private: - utils::ExceptionSpecAnalyzer SpecAnalyzer; + +protected: + DiagnosticBuilder + reportMissingNoexcept(const FunctionDecl *FuncDecl) final override; + void reportNoexceptEvaluatedToFalse(const FunctionDecl *FuncDecl, + const Expr *NoexceptExpr) final override; }; } // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp @@ -7,10 +7,7 @@ //===----------------------------------------------------------------------===// #include "NoexceptSwapCheck.h" -#include "../utils/LexerUtils.h" -#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; @@ -18,40 +15,20 @@ void NoexceptSwapCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - functionDecl(unless(isDeleted()), hasName("swap")).bind("decl"), this); + functionDecl(unless(isDeleted()), hasName("swap")).bind(BindFuncDeclName), + this); } -void NoexceptSwapCheck::check(const MatchFinder::MatchResult &Result) { - const auto *FuncDecl = Result.Nodes.getNodeAs("decl"); - assert(FuncDecl); - - if (SpecAnalyzer.analyze(FuncDecl) != - utils::ExceptionSpecAnalyzer::State::Throwing) - return; - - // Don't complain about nothrow(false), but complain on nothrow(expr) - // where expr evaluates to false. - const auto *ProtoType = FuncDecl->getType()->castAs(); - const Expr *NoexceptExpr = ProtoType->getNoexceptExpr(); - if (NoexceptExpr) { - NoexceptExpr = NoexceptExpr->IgnoreImplicit(); - if (!isa(NoexceptExpr)) { - diag(NoexceptExpr->getExprLoc(), - "noexcept specifier on swap function evaluates to 'false'"); - } - return; - } - - auto Diag = diag(FuncDecl->getLocation(), "swap functions should " - "be marked noexcept"); - - // Add FixIt hints. - const SourceManager &SM = *Result.SourceManager; +DiagnosticBuilder +NoexceptSwapCheck::reportMissingNoexcept(const FunctionDecl *FuncDecl) { + return diag(FuncDecl->getLocation(), "swap functions should " + "be marked noexcept"); +} - const SourceLocation NoexceptLoc = - utils::lexer::getLocationForNoexceptSpecifier(FuncDecl, SM); - if (NoexceptLoc.isValid()) - Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept "); +void NoexceptSwapCheck::reportNoexceptEvaluatedToFalse( + const FunctionDecl *FuncDecl, const Expr *NoexceptExpr) { + diag(NoexceptExpr->getExprLoc(), + "noexcept specifier on swap function evaluates to 'false'"); } } // namespace clang::tidy::performance