//===--- UseEqualsDeleteCheck.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 "UseEqualsDeleteCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang::tidy::modernize { namespace { AST_MATCHER(FunctionDecl, hasAnyDefinition) { if (Node.hasBody() || Node.isPureVirtual() || Node.isDefaulted() || Node.isDeleted()) return true; if (const FunctionDecl *Definition = Node.getDefinition()) if (Definition->hasBody() || Definition->isPureVirtual() || Definition->isDefaulted() || Definition->isDeleted()) return true; return false; } AST_MATCHER(Decl, isUsed) { return Node.isUsed(); } AST_MATCHER(CXXMethodDecl, isSpecialFunction) { if (const auto *Constructor = dyn_cast(&Node)) return Constructor->isDefaultConstructor() || Constructor->isCopyOrMoveConstructor(); return isa(Node) || Node.isCopyAssignmentOperator() || Node.isMoveAssignmentOperator(); } } // namespace static const char SpecialFunction[] = "SpecialFunction"; static const char DeletedNotPublic[] = "DeletedNotPublic"; UseEqualsDeleteCheck::UseEqualsDeleteCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)) {} void UseEqualsDeleteCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreMacros", IgnoreMacros); } void UseEqualsDeleteCheck::registerMatchers(MatchFinder *Finder) { auto PrivateSpecialFn = cxxMethodDecl(isPrivate(), isSpecialFunction()); Finder->addMatcher( cxxMethodDecl( PrivateSpecialFn, unless(hasAnyDefinition()), unless(isUsed()), // Ensure that all methods except private special member functions are // defined. unless(ofClass(hasMethod(cxxMethodDecl(unless(PrivateSpecialFn), unless(hasAnyDefinition())))))) .bind(SpecialFunction), this); Finder->addMatcher( cxxMethodDecl(isDeleted(), unless(isPublic())).bind(DeletedNotPublic), this); } void UseEqualsDeleteCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Func = Result.Nodes.getNodeAs(SpecialFunction)) { SourceLocation EndLoc = Lexer::getLocForEndOfToken( Func->getEndLoc(), 0, *Result.SourceManager, getLangOpts()); if (IgnoreMacros && Func->getLocation().isMacroID()) return; // FIXME: Improve FixItHint to make the method public. diag(Func->getLocation(), "use '= delete' to prohibit calling of a special member function") << FixItHint::CreateInsertion(EndLoc, " = delete"); } else if (const auto *Func = Result.Nodes.getNodeAs(DeletedNotPublic)) { // Ignore this warning in macros, since it's extremely noisy in code using // DISALLOW_COPY_AND_ASSIGN-style macros and there's no easy way to // automatically fix the warning when macros are in play. if (IgnoreMacros && Func->getLocation().isMacroID()) return; // FIXME: Add FixItHint to make the method public. diag(Func->getLocation(), "deleted member function should be public"); } } } // namespace clang::tidy::modernize