static const char SpecialFunction[] = "SpecialFunction";
-/// \brief Finds the SourceLocation of the colon ':' before the initialization
-/// list in the definition of a constructor.
-static SourceLocation getColonLoc(const ASTContext *Context,
- const CXXConstructorDecl *Ctor) {
- // FIXME: First init is the first initialization that is going to be
- // performed, no matter what was the real order in the source code. If the
- // order of the inits is wrong in the code, it may result in a false negative.
- SourceLocation FirstInit = (*Ctor->init_begin())->getSourceLocation();
- SourceLocation LastArg =
- Ctor->getParamDecl(Ctor->getNumParams() - 1)->getLocEnd();
- // We need to find the colon between the ')' and the first initializer.
- bool Invalid = false;
- StringRef Text = Lexer::getSourceText(
- CharSourceRange::getCharRange(LastArg, FirstInit),
- Context->getSourceManager(), Context->getLangOpts(), &Invalid);
- if (Invalid)
- return SourceLocation();
-
- size_t ColonPos = Text.rfind(':');
- if (ColonPos == StringRef::npos)
- return SourceLocation();
-
- Text = Text.drop_front(ColonPos + 1);
- if (std::strspn(Text.data(), " \t\r\n") != Text.size()) {
- // If there are comments, preprocessor directives or anything, abort.
- return SourceLocation();
- }
- // FIXME: don't remove comments in the middle of the initializers.
- return LastArg.getLocWithOffset(ColonPos);
-}
-
/// \brief Finds all the named non-static fields of \p Record.
static std::set<const FieldDecl *>
getAllNamedFields(const CXXRecordDecl *Record) {
void UseDefaultCheck::check(const MatchFinder::MatchResult &Result) {
std::string SpecialFunctionName;
- SourceLocation StartLoc, EndLoc;
// Both CXXConstructorDecl and CXXDestructorDecl inherit from CXXMethodDecl.
const auto *SpecialFunctionDecl =
if (!Body)
return;
- // Default locations.
- StartLoc = Body->getLBracLoc();
- EndLoc = Body->getRBracLoc();
-
// If there are comments inside the body, don't do the change.
if (!SpecialFunctionDecl->isCopyAssignmentOperator() &&
!bodyEmpty(Result.Context, Body))
return;
+ std::vector<FixItHint> RemoveInitializers;
+
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(SpecialFunctionDecl)) {
if (Ctor->getNumParams() == 0) {
SpecialFunctionName = "default constructor";
return;
SpecialFunctionName = "copy constructor";
// If there are constructor initializers, they must be removed.
- if (Ctor->getNumCtorInitializers() != 0) {
- StartLoc = getColonLoc(Result.Context, Ctor);
- if (!StartLoc.isValid())
- return;
+ for (const CXXCtorInitializer *Init : Ctor->inits()) {
+ RemoveInitializers.emplace_back(
+ FixItHint::CreateRemoval(Init->getSourceRange()));
}
}
} else if (isa<CXXDestructorDecl>(SpecialFunctionDecl)) {
diag(SpecialFunctionDecl->getLocStart(),
"use '= default' to define a trivial " + SpecialFunctionName)
- << FixItHint::CreateReplacement(
- CharSourceRange::getTokenRange(StartLoc, EndLoc), "= default;");
+ << FixItHint::CreateReplacement(Body->getSourceRange(), "= default;")
+ << RemoveInitializers;
}
} // namespace modernize
};
OL::OL(const OL &Other) : Field(Other.Field) {}
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor [modernize-use-default]
-// CHECK-FIXES: OL::OL(const OL &Other) = default;
+// CHECK-FIXES: OL::OL(const OL &Other) = default;
OL &OL::operator=(const OL &Other) {
Field = Other.Field;
return *this;
struct IL {
IL(const IL &Other) : Field(Other.Field) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: IL(const IL &Other) = default;
+ // CHECK-FIXES: IL(const IL &Other) = default;
IL &operator=(const IL &Other) {
Field = Other.Field;
return *this;
Mutable(Other.Mutable), Reference(Other.Reference),
Const(Other.Const) {}
// CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default'
- // CHECK-FIXES: Qual(const Qual &Other) = default;
+ // CHECK-FIXES: Qual(const Qual &Other)
+ // CHECK-FIXES: = default;
int Field;
volatile char Volatile;
struct Comments {
Comments(const Comments &Other)
/* don't delete */ : /* this comment */ Field(Other.Field) {}
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
+ // CHECK-FIXES: /* don't delete */ = default;
int Field;
};
struct ColonInComment {
ColonInComment(const ColonInComment &Other) /* : */ : Field(Other.Field) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: ColonInComment(const ColonInComment &Other) /* : */ = default;
+ // CHECK-FIXES: ColonInComment(const ColonInComment &Other) /* : */ = default;
int Field;
};
BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3),
Field4(Other.Field4) {}
// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
- // CHECK-FIXES: BF(const BF &Other) = default;
+ // CHECK-FIXES: BF(const BF &Other) {{$}}
+ // CHECK-FIXES: = default;
BF &operator=(const BF &);
unsigned Field1 : 3;
struct BC : IL, OL, BF {
BC(const BC &Other) : IL(Other), OL(Other), BF(Other) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: BC(const BC &Other) = default;
+ // CHECK-FIXES: BC(const BC &Other) = default;
BC &operator=(const BC &Other);
};
BC &BC::operator=(const BC &Other) {
struct BCWM : IL, OL {
BCWM(const BCWM &Other) : IL(Other), OL(Other), Bf(Other.Bf) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: BCWM(const BCWM &Other) = default;
+ // CHECK-FIXES: BCWM(const BCWM &Other) = default;
BCWM &operator=(const BCWM &);
BF Bf;
};
// is a virtual OL at the beginning of VA (which is the same).
VBC(const VBC &Other) : OL(Other), VA(Other), VB(Other) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: VBC(const VBC &Other) = default;
+ // CHECK-FIXES: VBC(const VBC &Other) = default;
VBC &operator=(const VBC &Other);
};
VBC &VBC::operator=(const VBC &Other) {
struct NCRef {
NCRef(NCRef &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
- // CHECK-FIXES: NCRef(NCRef &Other) = default;
+ // CHECK-FIXES: NCRef(NCRef &Other) = default;
NCRef &operator=(NCRef &);
int Field1, Field2;
};