Skip to content

Commit 47b6a30

Browse files
author
Jenkins
committed
merge main into amd-staging
Change-Id: I2cd6079ebcf03d73978a89cbb86e45f76567baea
2 parents b2a2273 + 7f1d757 commit 47b6a30

File tree

7 files changed

+218
-36
lines changed

7 files changed

+218
-36
lines changed

clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,14 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
291291
OpCode == BinaryOperatorKind::BO_NE))
292292
return;
293293

294-
// Always true, no warnings for that.
295-
if ((OpCode == BinaryOperatorKind::BO_GE && Value == 0 && ContainerIsLHS) ||
296-
(OpCode == BinaryOperatorKind::BO_LE && Value == 0 && !ContainerIsLHS))
297-
return;
294+
// Always true/false, no warnings for that.
295+
if (Value == 0) {
296+
if ((OpCode == BinaryOperatorKind::BO_GT && !ContainerIsLHS) ||
297+
(OpCode == BinaryOperatorKind::BO_LT && ContainerIsLHS) ||
298+
(OpCode == BinaryOperatorKind::BO_LE && !ContainerIsLHS) ||
299+
(OpCode == BinaryOperatorKind::BO_GE && ContainerIsLHS))
300+
return;
301+
}
298302

299303
// Do not warn for size > 1, 1 < size, size <= 1, 1 >= size.
300304
if (Value == 1) {
@@ -306,12 +310,32 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
306310
return;
307311
}
308312

313+
// Do not warn for size < 1, 1 > size, size <= 0, 0 >= size for non signed
314+
// types
315+
if ((OpCode == BinaryOperatorKind::BO_GT && Value == 1 &&
316+
!ContainerIsLHS) ||
317+
(OpCode == BinaryOperatorKind::BO_LT && Value == 1 && ContainerIsLHS) ||
318+
(OpCode == BinaryOperatorKind::BO_GE && Value == 0 &&
319+
!ContainerIsLHS) ||
320+
(OpCode == BinaryOperatorKind::BO_LE && Value == 0 && ContainerIsLHS)) {
321+
const Expr *Container = ContainerIsLHS
322+
? BinaryOp->getLHS()->IgnoreImpCasts()
323+
: BinaryOp->getRHS()->IgnoreImpCasts();
324+
if (Container->getType()
325+
.getCanonicalType()
326+
.getNonReferenceType()
327+
->isSignedIntegerType())
328+
return;
329+
}
330+
309331
if (OpCode == BinaryOperatorKind::BO_NE && Value == 0)
310332
Negation = true;
333+
311334
if ((OpCode == BinaryOperatorKind::BO_GT ||
312335
OpCode == BinaryOperatorKind::BO_GE) &&
313336
ContainerIsLHS)
314337
Negation = true;
338+
315339
if ((OpCode == BinaryOperatorKind::BO_LT ||
316340
OpCode == BinaryOperatorKind::BO_LE) &&
317341
!ContainerIsLHS)

clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "RedundantMemberInitCheck.h"
10+
#include "../utils/LexerUtils.h"
1011
#include "../utils/Matchers.h"
1112
#include "clang/AST/ASTContext.h"
1213
#include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -18,52 +19,80 @@ using namespace clang::tidy::matchers;
1819

1920
namespace clang::tidy::readability {
2021

22+
static SourceRange
23+
getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM,
24+
const LangOptions &LangOpts) {
25+
const Token PrevToken =
26+
utils::lexer::getPreviousToken(Range.getBegin(), SM, LangOpts, false);
27+
if (PrevToken.is(tok::unknown))
28+
return Range;
29+
30+
if (PrevToken.isNot(tok::equal))
31+
return {PrevToken.getEndLoc(), Range.getEnd()};
32+
33+
return getFullInitRangeInclWhitespaces(
34+
{PrevToken.getLocation(), Range.getEnd()}, SM, LangOpts);
35+
}
36+
2137
void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
2238
Options.store(Opts, "IgnoreBaseInCopyConstructors",
2339
IgnoreBaseInCopyConstructors);
2440
}
2541

2642
void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
43+
auto ConstructorMatcher =
44+
cxxConstructExpr(argumentCountIs(0),
45+
hasDeclaration(cxxConstructorDecl(ofClass(cxxRecordDecl(
46+
unless(isTriviallyDefaultConstructible()))))))
47+
.bind("construct");
48+
2749
Finder->addMatcher(
2850
cxxConstructorDecl(
2951
unless(isDelegatingConstructor()), ofClass(unless(isUnion())),
3052
forEachConstructorInitializer(
31-
cxxCtorInitializer(
32-
withInitializer(
33-
cxxConstructExpr(
34-
hasDeclaration(
35-
cxxConstructorDecl(ofClass(cxxRecordDecl(
36-
unless(isTriviallyDefaultConstructible()))))))
37-
.bind("construct")),
38-
unless(forField(hasType(isConstQualified()))),
39-
unless(forField(hasParent(recordDecl(isUnion())))))
53+
cxxCtorInitializer(withInitializer(ConstructorMatcher),
54+
unless(forField(fieldDecl(
55+
anyOf(hasType(isConstQualified()),
56+
hasParent(recordDecl(isUnion())))))))
4057
.bind("init")))
4158
.bind("constructor"),
4259
this);
60+
61+
Finder->addMatcher(fieldDecl(hasInClassInitializer(ConstructorMatcher),
62+
unless(hasParent(recordDecl(isUnion()))))
63+
.bind("field"),
64+
this);
4365
}
4466

4567
void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
46-
const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
4768
const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
69+
70+
if (const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field")) {
71+
const Expr *Init = Field->getInClassInitializer();
72+
diag(Construct->getExprLoc(), "initializer for member %0 is redundant")
73+
<< Field
74+
<< FixItHint::CreateRemoval(getFullInitRangeInclWhitespaces(
75+
Init->getSourceRange(), *Result.SourceManager, getLangOpts()));
76+
return;
77+
}
78+
79+
const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
4880
const auto *ConstructorDecl =
4981
Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
5082

5183
if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
5284
Init->isBaseInitializer())
5385
return;
5486

55-
if (Construct->getNumArgs() == 0 ||
56-
Construct->getArg(0)->isDefaultArgument()) {
57-
if (Init->isAnyMemberInitializer()) {
58-
diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
59-
<< Init->getAnyMember()
60-
<< FixItHint::CreateRemoval(Init->getSourceRange());
61-
} else {
62-
diag(Init->getSourceLocation(),
63-
"initializer for base class %0 is redundant")
64-
<< Construct->getType()
65-
<< FixItHint::CreateRemoval(Init->getSourceRange());
66-
}
87+
if (Init->isAnyMemberInitializer()) {
88+
diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
89+
<< Init->getAnyMember()
90+
<< FixItHint::CreateRemoval(Init->getSourceRange());
91+
} else {
92+
diag(Init->getSourceLocation(),
93+
"initializer for base class %0 is redundant")
94+
<< Construct->getType()
95+
<< FixItHint::CreateRemoval(Init->getSourceRange());
6796
}
6897
}
6998

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,9 @@ Changes in existing checks
467467
- Improved :doc:`readability-container-size-empty
468468
<clang-tidy/checks/readability/container-size-empty>` check to
469469
detect comparison between string and empty string literals and support
470-
``length()`` method as an alternative to ``size()``.
470+
``length()`` method as an alternative to ``size()``. Resolved false positives
471+
tied to negative values from size-like methods, and one triggered by size
472+
checks below zero.
471473

472474
- Improved :doc:`readability-function-size
473475
<clang-tidy/checks/readability/function-size>` check configuration to use
@@ -501,6 +503,10 @@ Changes in existing checks
501503
<clang-tidy/checks/readability/non-const-parameter>` check to ignore
502504
false-positives in initializer list of record.
503505

506+
- Improved :doc:`readability-redundant-member-init
507+
<clang-tidy/checks/readability/redundant-member-init>` check to now also
508+
detect redundant in-class initializers.
509+
504510
- Improved :doc:`readability-simplify-boolean-expr
505511
<clang-tidy/checks/readability/simplify-boolean-expr>` check by adding the
506512
new option `IgnoreMacros` that allows to ignore boolean expressions originating

clang-tools-extra/docs/clang-tidy/checks/readability/redundant-member-init.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ Example
1111

1212
.. code-block:: c++
1313

14-
// Explicitly initializing the member s is unnecessary.
14+
// Explicitly initializing the member s and v is unnecessary.
1515
class Foo {
1616
public:
1717
Foo() : s() {}
1818

1919
private:
2020
std::string s;
21+
std::vector<int> v {};
2122
};
2223

2324
Options

clang-tools-extra/test/clang-tidy/checkers/readability/container-size-empty.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class TemplatedContainer {
3333
public:
3434
bool operator==(const TemplatedContainer<T>& other) const;
3535
bool operator!=(const TemplatedContainer<T>& other) const;
36-
int size() const;
36+
unsigned long size() const;
3737
bool empty() const;
3838
};
3939

@@ -42,7 +42,7 @@ class PrivateEmpty {
4242
public:
4343
bool operator==(const PrivateEmpty<T>& other) const;
4444
bool operator!=(const PrivateEmpty<T>& other) const;
45-
int size() const;
45+
unsigned long size() const;
4646
private:
4747
bool empty() const;
4848
};
@@ -61,7 +61,7 @@ struct EnumSize {
6161
class Container {
6262
public:
6363
bool operator==(const Container& other) const;
64-
int size() const;
64+
unsigned long size() const;
6565
bool empty() const;
6666
};
6767

@@ -70,13 +70,13 @@ class Derived : public Container {
7070

7171
class Container2 {
7272
public:
73-
int size() const;
73+
unsigned long size() const;
7474
bool empty() const { return size() == 0; }
7575
};
7676

7777
class Container3 {
7878
public:
79-
int size() const;
79+
unsigned long size() const;
8080
bool empty() const;
8181
};
8282

@@ -85,7 +85,7 @@ bool Container3::empty() const { return this->size() == 0; }
8585
class Container4 {
8686
public:
8787
bool operator==(const Container4& rhs) const;
88-
int size() const;
88+
unsigned long size() const;
8989
bool empty() const { return *this == Container4(); }
9090
};
9191

@@ -815,3 +815,49 @@ bool testNotEmptyStringLiterals(const std::string& s)
815815
using namespace std::string_literals;
816816
return s == "foo"s;
817817
}
818+
819+
namespace PR72619 {
820+
struct SS {
821+
bool empty() const;
822+
int size() const;
823+
};
824+
825+
struct SU {
826+
bool empty() const;
827+
unsigned size() const;
828+
};
829+
830+
void f(const SU& s) {
831+
if (s.size() < 0) {}
832+
if (0 > s.size()) {}
833+
if (s.size() >= 0) {}
834+
if (0 <= s.size()) {}
835+
if (s.size() < 1)
836+
;
837+
// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
838+
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
839+
if (1 > s.size())
840+
;
841+
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
842+
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
843+
if (s.size() <= 0)
844+
;
845+
// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
846+
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
847+
if (0 >= s.size())
848+
;
849+
// CHECK-MESSAGES: :[[@LINE-2]]:14: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
850+
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
851+
}
852+
853+
void f(const SS& s) {
854+
if (s.size() < 0) {}
855+
if (0 > s.size()) {}
856+
if (s.size() >= 0) {}
857+
if (0 <= s.size()) {}
858+
if (s.size() < 1) {}
859+
if (1 > s.size()) {}
860+
if (s.size() <= 0) {}
861+
if (0 >= s.size()) {}
862+
}
863+
}

clang-tools-extra/test/clang-tidy/checkers/readability/redundant-member-init.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,55 @@ struct NF15 {
250250
S s2;
251251
};
252252
};
253+
254+
// Direct in-class initialization with default constructor
255+
struct D1 {
256+
S f1 {};
257+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f1' is redundant
258+
// CHECK-FIXES: S f1;
259+
};
260+
261+
// Direct in-class initialization with constructor with default argument
262+
struct D2 {
263+
T f2 {};
264+
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: initializer for member 'f2' is redundant
265+
// CHECK-FIXES: T f2;
266+
};
267+
268+
// Direct in-class initialization with default constructor (assign)
269+
struct D3 {
270+
S f3 = {};
271+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f3' is redundant
272+
// CHECK-FIXES: S f3;
273+
};
274+
275+
// Direct in-class initialization with constructor with default argument (assign)
276+
struct D4 {
277+
T f4 = {};
278+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f4' is redundant
279+
// CHECK-FIXES: T f4;
280+
};
281+
282+
// Templated class independent type
283+
template <class V>
284+
struct D5 {
285+
S f5 /*comment*/ = S();
286+
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: initializer for member 'f5' is redundant
287+
// CHECK-FIXES: S f5 /*comment*/;
288+
};
289+
D5<int> d5i;
290+
D5<S> d5s;
291+
292+
struct D6 {
293+
UsesCleanup uc2{};
294+
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer for member 'uc2' is redundant
295+
// CHECK-FIXES: UsesCleanup uc2;
296+
};
297+
298+
template<typename V>
299+
struct D7 {
300+
V f7;
301+
};
302+
303+
D7<int> d7i;
304+
D7<S> d7s;

0 commit comments

Comments
 (0)