Skip to content

Commit 24aafca

Browse files
author
Mitchell Balan
committed
[clang-tidy] modernize-use-equals-default avoid adding redundant semicolons
Summary: `modernize-use-equals-default` replaces default constructors/destructors with `= default;`. When the optional semicolon after a member function is present, this results in two consecutive semicolons. This patch checks to see if the next non-comment token after the code to be replaced is a semicolon, and if so offers a replacement of `= default` rather than `= default;`. This patch adds trailing comments and semicolons to about 5 existing tests. Reviewers: malcolm.parsons, angelgarcia, aaron.ballman, alexfh Patch by: poelmanc Subscribers: MyDeveloperDay, JonasToth, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D70144
1 parent a329cf6 commit 24aafca

File tree

6 files changed

+41
-12
lines changed

6 files changed

+41
-12
lines changed

clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "clang/AST/ASTContext.h"
1111
#include "clang/ASTMatchers/ASTMatchFinder.h"
1212
#include "clang/Lex/Lexer.h"
13+
#include "../utils/LexerUtils.h"
1314

1415
using namespace clang::ast_matchers;
1516

@@ -302,9 +303,16 @@ void UseEqualsDefaultCheck::check(const MatchFinder::MatchResult &Result) {
302303
auto Diag = diag(Location, "use '= default' to define a trivial " +
303304
SpecialFunctionName);
304305

305-
if (ApplyFix)
306-
Diag << FixItHint::CreateReplacement(Body->getSourceRange(), "= default;")
306+
if (ApplyFix) {
307+
// Skipping comments, check for a semicolon after Body->getSourceRange()
308+
Optional<Token> Token = utils::lexer::findNextTokenSkippingComments(
309+
Body->getSourceRange().getEnd().getLocWithOffset(1),
310+
Result.Context->getSourceManager(), Result.Context->getLangOpts());
311+
StringRef Replacement =
312+
Token && Token->is(tok::semi) ? "= default" : "= default;";
313+
Diag << FixItHint::CreateReplacement(Body->getSourceRange(), Replacement)
307314
<< RemoveInitializers;
315+
}
308316
}
309317

310318
} // namespace modernize

clang-tools-extra/clang-tidy/utils/LexerUtils.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
6868
return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi);
6969
}
7070

71+
Optional<Token> findNextTokenSkippingComments(SourceLocation Start,
72+
const SourceManager &SM,
73+
const LangOptions &LangOpts) {
74+
Optional<Token> CurrentToken;
75+
do {
76+
CurrentToken = Lexer::findNextToken(Start, SM, LangOpts);
77+
} while (CurrentToken && CurrentToken->is(tok::comment));
78+
return CurrentToken;
79+
}
80+
7181
bool rangeContainsExpansionsOrDirectives(SourceRange Range,
7282
const SourceManager &SM,
7383
const LangOptions &LangOpts) {

clang-tools-extra/clang-tidy/utils/LexerUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ SourceLocation findNextAnyTokenKind(SourceLocation Start,
8080
}
8181
}
8282

83+
// Finds next token that's not a comment.
84+
Optional<Token> findNextTokenSkippingComments(SourceLocation Start,
85+
const SourceManager &SM,
86+
const LangOptions &LangOpts);
87+
8388
/// Re-lex the provide \p Range and return \c false if either a macro spans
8489
/// multiple tokens, a pre-processor directive or failure to retrieve the
8590
/// next token is found, otherwise \c true.

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ Improvements to clang-tidy
158158
- The 'objc-avoid-spinlock' check was renamed to :doc:`darwin-avoid-spinlock
159159
<clang-tidy/checks/darwin-avoid-spinlock>`
160160

161+
- The :doc:`modernize-use-equals-default
162+
<clang-tidy/checks/modernize-use-equals-default>` fix no longer adds
163+
semicolons where they would be redundant.
164+
161165
- New :doc:`readability-redundant-access-specifiers
162166
<clang-tidy/checks/readability-redundant-access-specifiers>` check.
163167

clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default-copy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Empty &Empty::operator=(const Empty &Other) { return *this; }
119119
struct BF {
120120
BF() = default;
121121
BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3),
122-
Field4(Other.Field4) {}
122+
Field4(Other.Field4) {};
123123
// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
124124
// CHECK-FIXES: BF(const BF &Other) {{$}}
125125
// CHECK-FIXES: = default;

clang-tools-extra/test/clang-tidy/checkers/modernize-use-equals-default.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class OL {
77
~OL();
88
};
99

10-
OL::OL() {}
10+
OL::OL() {};
1111
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial default constructor [modernize-use-equals-default]
1212
// CHECK-FIXES: OL::OL() = default;
1313
OL::~OL() {}
@@ -17,9 +17,9 @@ OL::~OL() {}
1717
// Inline definitions.
1818
class IL {
1919
public:
20-
IL() {}
20+
IL() {} ; // Note embedded tab on this line
2121
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
22-
// CHECK-FIXES: IL() = default;
22+
// CHECK-FIXES: IL() = default ; // Note embedded tab on this line
2323
~IL() {}
2424
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
2525
// CHECK-FIXES: ~IL() = default;
@@ -46,18 +46,20 @@ class IA {
4646
// Default member initializer
4747
class DMI {
4848
public:
49-
DMI() {}
50-
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
51-
// CHECK-FIXES: DMI() = default;
49+
DMI() {} // Comment before semi-colon on next line
50+
;
51+
// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
52+
// CHECK-FIXES: DMI() = default // Comment before semi-colon on next line
53+
// CHECK-FIXES-NEXT: ;
5254
int Field = 5;
5355
};
5456

5557
// Class member
5658
class CM {
5759
public:
58-
CM() {}
60+
CM() {} /* Comments */ /* before */ /* semicolon */;
5961
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
60-
// CHECK-FIXES: CM() = default;
62+
// CHECK-FIXES: CM() = default /* Comments */ /* before */ /* semicolon */;
6163
OL o;
6264
};
6365

@@ -66,7 +68,7 @@ class Priv {
6668
Priv() {}
6769
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
6870
// CHECK-FIXES: Priv() = default;
69-
~Priv() {}
71+
~Priv() {};
7072
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
7173
// CHECK-FIXES: ~Priv() = default;
7274
};

0 commit comments

Comments
 (0)