12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Lex/Lexer.h"
25static llvm::SmallPtrSet<const FieldDecl *, 0>
27 llvm::SmallPtrSet<const FieldDecl *, 0> Result;
28 for (
const auto *Field : Record->fields()) {
30 if (Field->isUnnamedBitField())
39static llvm::SmallPtrSet<const Type *, 0>
41 llvm::SmallPtrSet<const Type *, 0> Result;
42 for (
const auto Base : Record->bases()) {
44 const auto *BaseType = Base.getTypeSourceInfo()->getType().getTypePtr();
45 Result.insert(BaseType);
53static ast_matchers::internal::Matcher<Expr>
55 return ignoringImpCasts(
56 memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
57 member(fieldDecl(equalsNode(Field)))));
63 const CXXConstructorDecl *Ctor) {
65 if (Ctor->getMinRequiredArguments() != 1)
68 const auto *Record = Ctor->getParent();
69 const auto *Param = Ctor->getParamDecl(0);
76 for (
const auto *Base : BasesToInit) {
82 forEachConstructorInitializer(cxxCtorInitializer(
84 withInitializer(cxxConstructExpr(
85 hasType(equalsNode(Base)),
87 cxxConstructorDecl(isCopyConstructor())),
89 hasArgument(0, declRefExpr(to(varDecl(
90 equalsNode(Param))))))))))),
97 for (
const auto *Field : FieldsToInit) {
103 forEachConstructorInitializer(cxxCtorInitializer(
104 isMemberInitializer(), forField(equalsNode(Field)),
105 withInitializer(anyOf(
106 AccessToFieldInParam,
107 initListExpr(has(AccessToFieldInParam)),
110 cxxConstructorDecl(isCopyConstructor())),
112 hasArgument(0, AccessToFieldInParam)))))))),
119 return Ctor->getNumCtorInitializers() ==
120 BasesToInit.size() + FieldsToInit.size();
127 const CXXMethodDecl *Operator) {
128 const auto *Record = Operator->getParent();
129 const auto *Param = Operator->getParamDecl(0);
135 const auto *Compound = cast<CompoundStmt>(Operator->getBody());
140 if (Compound->body_empty() ||
143 returnStmt(has(ignoringParenImpCasts(unaryOperator(
144 hasOperatorName(
"*"), hasUnaryOperand(cxxThisExpr())))))),
145 *Compound->body_back(), *Context)
150 for (
const auto *Base : BasesToInit) {
160 compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
164 onImplicitObjectArgument(implicitCastExpr(
165 hasImplicitDestinationType(hasCanonicalType(pointsTo(
166 type(equalsNode(Base->getCanonicalTypeInternal()
168 hasSourceExpression(cxxThisExpr()))),
170 callee(cxxMethodDecl(isCopyAssignmentOperator())),
175 0, declRefExpr(to(varDecl(equalsNode(Param)))))))))),
182 for (
const auto *Field : FieldsToInit) {
187 const auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
188 member(fieldDecl(equalsNode(Field))));
190 if (match(traverse(TK_AsIs,
191 compoundStmt(has(ignoringParenImpCasts(binaryOperation(
192 hasOperatorName(
"="), hasLHS(LHS), hasRHS(RHS)))))),
199 return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
203static bool bodyEmpty(
const ASTContext *Context,
const CompoundStmt *Body) {
204 bool Invalid =
false;
205 const StringRef Text = Lexer::getSourceText(
206 CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
207 Body->getRBracLoc()),
208 Context->getSourceManager(), Context->getLangOpts(), &Invalid);
209 return !Invalid && Text.ltrim(
" \t\r\n").empty();
215 IgnoreMacros(Options.get(
"IgnoreMacros", true)) {}
218 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
224 const auto IsUnionLikeClass = recordDecl(
226 has(fieldDecl(isImplicit(), hasType(cxxRecordDecl(isUnion()))))));
228 const LangOptions &LangOpts = getLangOpts();
229 auto IsPublicOrOutOfLineUntilCPP20 =
231 ? cxxConstructorDecl()
232 : cxxConstructorDecl(anyOf(isOutOfLine(), isPublic()));
236 cxxDestructorDecl(isDefinition(), unless(ofClass(IsUnionLikeClass)))
242 isDefinition(), unless(ofClass(IsUnionLikeClass)),
243 unless(hasParent(functionTemplateDecl())),
246 allOf(parameterCountIs(0),
247 unless(hasAnyConstructorInitializer(
249 unless(withInitializer(cxxConstructExpr(
251 unless(requiresZeroInitialization()))))))),
252 unless(isVariadic()), IsPublicOrOutOfLineUntilCPP20),
254 allOf(isCopyConstructor(),
258 parameterCountIs(1))))
263 cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
264 unless(ofClass(IsUnionLikeClass)),
265 unless(hasParent(functionTemplateDecl())),
269 hasParameter(0, hasType(lValueReferenceType())),
272 returns(qualType(hasCanonicalType(
273 allOf(lValueReferenceType(pointee(type())),
274 unless(matchers::isReferenceToConst()))))))
281 const auto *SpecialFunctionDecl =
284 if (IgnoreMacros && SpecialFunctionDecl->getLocation().isMacroID())
289 if (SpecialFunctionDecl->isDeleted() ||
290 SpecialFunctionDecl->isExplicitlyDefaulted() ||
291 SpecialFunctionDecl->isLateTemplateParsed() ||
292 SpecialFunctionDecl->isTemplateInstantiation() ||
293 !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
296 const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
301 if (!SpecialFunctionDecl->isCopyAssignmentOperator() && !Body->body_empty())
306 Body->getSourceRange(), *Result.SourceManager,
307 Result.Context->getLangOpts()))
311 const bool ApplyFix = SpecialFunctionDecl->isCopyAssignmentOperator() ||
314 std::vector<FixItHint> RemoveInitializers;
315 unsigned MemberType = 0;
316 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
317 if (Ctor->getNumParams() == 0) {
325 for (
const auto *Init : Ctor->inits()) {
326 if (!Init->isWritten())
328 RemoveInitializers.emplace_back(
329 FixItHint::CreateRemoval(Init->getSourceRange()));
331 }
else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
341 SourceLocation
Location = SpecialFunctionDecl->getLocation();
345 const auto Diag = diag(
347 "use '= default' to define a trivial %select{default constructor|copy "
348 "constructor|destructor|copy-assignment operator}0");
353 *Body, Result.Context->getSourceManager(),
354 Result.Context->getLangOpts());
357 UnifiedEnd, Result.Context->getSourceManager(),
358 Result.Context->getLangOpts());
359 const StringRef Replacement =
360 Token && Token->is(tok::semi) ?
"= default" :
"= default;";
361 Diag << FixItHint::CreateReplacement(Body->getSourceRange(), Replacement)
362 << RemoveInitializers;
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
UseEqualsDefaultCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
static bool empty(SourceRange Range)
static ast_matchers::internal::Matcher< Expr > accessToFieldInVar(const FieldDecl *Field, const ValueDecl *Var)
Returns a matcher that matches member expressions where the base is the variable declared as Var and ...
static bool bodyEmpty(const ASTContext *Context, const CompoundStmt *Body)
Returns false if the body has any non-whitespace character.
static constexpr char SpecialFunction[]
static llvm::SmallPtrSet< const Type *, 0 > getAllDirectBases(const CXXRecordDecl *Record)
Returns the names of the direct bases of Record, both virtual and non-virtual.
static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context, const CXXConstructorDecl *Ctor)
Check that the given constructor has copy signature and that it copy-initializes all its bases and me...
static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context, const CXXMethodDecl *Operator)
Checks that the given method is an overloading of the assignment operator, has copy signature,...
static llvm::SmallPtrSet< const FieldDecl *, 0 > getAllNamedFields(const CXXRecordDecl *Record)
Finds all the named non-static fields of Record.
SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM, const LangOptions &LangOpts)
Stmt->getEndLoc does not always behave the same way depending on Token type.
bool rangeContainsExpansionsOrDirectives(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Re-lex the provide Range and return false if either a macro spans multiple tokens,...
std::optional< Token > findNextTokenSkippingComments(SourceLocation Start, const SourceManager &SM, const LangOptions &LangOpts)
llvm::StringMap< ClangTidyValue > OptionMap