99 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "UseEqualsDeleteCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/Lex/Lexer.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::modernize {17 18namespace {19AST_MATCHER(FunctionDecl, hasAnyDefinition) {20 if (Node.hasBody() || Node.isPureVirtual() || Node.isDefaulted() ||21 Node.isDeleted())22 return true;23 24 if (const FunctionDecl *Definition = Node.getDefinition())25 if (Definition->hasBody() || Definition->isPureVirtual() ||26 Definition->isDefaulted() || Definition->isDeleted())27 return true;28 29 return false;30}31 32AST_MATCHER(Decl, isUsed) { return Node.isUsed(); }33 34AST_MATCHER(CXXMethodDecl, isSpecialFunction) {35 if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(&Node))36 return Constructor->isDefaultConstructor() ||37 Constructor->isCopyOrMoveConstructor();38 39 return isa<CXXDestructorDecl>(Node) || Node.isCopyAssignmentOperator() ||40 Node.isMoveAssignmentOperator();41}42} // namespace43 44static const char SpecialFunction[] = "SpecialFunction";45static const char DeletedNotPublic[] = "DeletedNotPublic";46 47UseEqualsDeleteCheck::UseEqualsDeleteCheck(StringRef Name,48 ClangTidyContext *Context)49 : ClangTidyCheck(Name, Context),50 IgnoreMacros(Options.get("IgnoreMacros", true)) {}51 52void UseEqualsDeleteCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {53 Options.store(Opts, "IgnoreMacros", IgnoreMacros);54}55 56void UseEqualsDeleteCheck::registerMatchers(MatchFinder *Finder) {57 auto PrivateSpecialFn = cxxMethodDecl(isPrivate(), isSpecialFunction());58 59 Finder->addMatcher(60 cxxMethodDecl(61 PrivateSpecialFn, unless(hasAnyDefinition()), unless(isUsed()),62 // Ensure that all methods except private special member functions are63 // defined.64 unless(ofClass(hasMethod(cxxMethodDecl(unless(PrivateSpecialFn),65 unless(hasAnyDefinition()))))))66 .bind(SpecialFunction),67 this);68 69 Finder->addMatcher(70 cxxMethodDecl(isDeleted(), unless(isPublic())).bind(DeletedNotPublic),71 this);72}73 74void UseEqualsDeleteCheck::check(const MatchFinder::MatchResult &Result) {75 if (const auto *Func =76 Result.Nodes.getNodeAs<CXXMethodDecl>(SpecialFunction)) {77 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(78 Func->getEndLoc(), 0, *Result.SourceManager, getLangOpts());79 80 if (IgnoreMacros && Func->getLocation().isMacroID())81 return;82 // FIXME: Improve FixItHint to make the method public.83 diag(Func->getLocation(),84 "use '= delete' to prohibit calling of a special member function")85 << FixItHint::CreateInsertion(EndLoc, " = delete");86 } else if (const auto *Func =87 Result.Nodes.getNodeAs<CXXMethodDecl>(DeletedNotPublic)) {88 // Ignore this warning in macros, since it's extremely noisy in code using89 // DISALLOW_COPY_AND_ASSIGN-style macros and there's no easy way to90 // automatically fix the warning when macros are in play.91 if (IgnoreMacros && Func->getLocation().isMacroID())92 return;93 // FIXME: Add FixItHint to make the method public.94 diag(Func->getLocation(), "deleted member function should be public");95 }96}97 98} // namespace clang::tidy::modernize99