10 #include "../utils/LexerUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
24 static std::set<const FieldDecl *>
26 std::set<const FieldDecl *> Result;
29 if (
Field->isUnnamedBitfield())
39 std::set<const Type *> Result;
42 const auto *BaseType =
Base.getTypeSourceInfo()->getType().getTypePtr();
43 Result.insert(BaseType);
52 const ValueDecl *Var) {
53 return ignoringImpCasts(
54 memberExpr(hasObjectExpression(declRefExpr(to(varDecl(equalsNode(Var))))),
55 member(fieldDecl(equalsNode(
Field)))));
61 const CXXConstructorDecl *Ctor) {
63 if (Ctor->getMinRequiredArguments() != 1)
66 const auto *
Record = Ctor->getParent();
67 const auto *Param = Ctor->getParamDecl(0);
74 for (
const auto *
Base : BasesToInit) {
80 forEachConstructorInitializer(cxxCtorInitializer(
82 withInitializer(cxxConstructExpr(
83 hasType(equalsNode(
Base)),
85 cxxConstructorDecl(isCopyConstructor())),
87 hasArgument(0, declRefExpr(to(varDecl(
88 equalsNode(Param))))))))))),
95 for (
const auto *
Field : FieldsToInit) {
101 forEachConstructorInitializer(cxxCtorInitializer(
102 isMemberInitializer(), forField(equalsNode(
Field)),
103 withInitializer(anyOf(
104 AccessToFieldInParam,
105 initListExpr(has(AccessToFieldInParam)),
108 cxxConstructorDecl(isCopyConstructor())),
110 hasArgument(0, AccessToFieldInParam)))))))),
117 return Ctor->getNumCtorInitializers() ==
118 BasesToInit.size() + FieldsToInit.size();
125 const CXXMethodDecl *Operator) {
126 const auto *
Record = Operator->getParent();
127 const auto *Param = Operator->getParamDecl(0);
133 const auto *Compound = cast<CompoundStmt>(Operator->getBody());
138 if (Compound->body_empty() ||
141 returnStmt(has(ignoringParenImpCasts(unaryOperator(
142 hasOperatorName(
"*"), hasUnaryOperand(cxxThisExpr())))))),
143 *Compound->body_back(), *Context)
148 for (
const auto *
Base : BasesToInit) {
156 if (
match(traverse(TK_AsIs,
157 compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr(
161 onImplicitObjectArgument(implicitCastExpr(
162 hasImplicitDestinationType(
163 pointsTo(type(equalsNode(
Base)))),
164 hasSourceExpression(cxxThisExpr()))),
166 callee(cxxMethodDecl(isCopyAssignmentOperator())),
170 hasArgument(0, declRefExpr(to(varDecl(
171 equalsNode(Param)))))))))),
178 for (
const auto *
Field : FieldsToInit) {
183 auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
184 member(fieldDecl(equalsNode(
Field))));
186 if (
match(traverse(TK_AsIs,
187 compoundStmt(has(ignoringParenImpCasts(binaryOperation(
188 hasOperatorName(
"="), hasLHS(LHS), hasRHS(RHS)))))),
195 return Compound->size() == BasesToInit.size() + FieldsToInit.size() + 1;
199 static bool bodyEmpty(
const ASTContext *Context,
const CompoundStmt *Body) {
200 bool Invalid =
false;
202 CharSourceRange::getCharRange(Body->getLBracLoc().getLocWithOffset(1),
203 Body->getRBracLoc()),
204 Context->getSourceManager(), Context->getLangOpts(), &Invalid);
205 return !Invalid && std::strspn(
Text.data(),
" \t\r\n") ==
Text.size();
208 UseEqualsDefaultCheck::UseEqualsDefaultCheck(StringRef
Name,
211 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)) {}
219 Finder->addMatcher(cxxDestructorDecl(isDefinition()).bind(
SpecialFunction),
226 allOf(unless(hasAnyConstructorInitializer(isWritten())),
227 parameterCountIs(0)),
229 allOf(isCopyConstructor(),
233 parameterCountIs(1))))
238 cxxMethodDecl(isDefinition(), isCopyAssignmentOperator(),
242 hasParameter(0, hasType(lValueReferenceType())))
249 const auto *SpecialFunctionDecl =
252 if (IgnoreMacros && SpecialFunctionDecl->getLocation().isMacroID())
257 if (SpecialFunctionDecl->isDeleted() ||
258 SpecialFunctionDecl->isExplicitlyDefaulted() ||
259 SpecialFunctionDecl->isLateTemplateParsed() ||
260 SpecialFunctionDecl->isTemplateInstantiation() ||
261 !SpecialFunctionDecl->isUserProvided() || !SpecialFunctionDecl->hasBody())
264 const auto *Body = dyn_cast<CompoundStmt>(SpecialFunctionDecl->getBody());
269 if (!SpecialFunctionDecl->isCopyAssignmentOperator() && !Body->body_empty())
273 bool ApplyFix = SpecialFunctionDecl->isCopyAssignmentOperator() ||
276 std::vector<FixItHint> RemoveInitializers;
278 if (
const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
279 if (Ctor->getNumParams() == 0) {
286 for (
const auto *Init : Ctor->inits()) {
287 RemoveInitializers.emplace_back(
288 FixItHint::CreateRemoval(Init->getSourceRange()));
291 }
else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
301 SourceLocation
Location = SpecialFunctionDecl->getLocation();
307 "use '= default' to define a trivial %select{default constructor|copy "
308 "constructor|destructor|copy-assignment operator}0");
314 Body->getSourceRange().getEnd().getLocWithOffset(1),
315 Result.Context->getSourceManager(), Result.Context->getLangOpts());
316 StringRef Replacement =
317 Token && Token->is(tok::semi) ?
"= default" :
"= default;";
318 Diag << FixItHint::CreateReplacement(Body->getSourceRange(), Replacement)
319 << RemoveInitializers;