Skip to content

Commit 42b9448

Browse files
committed
Fully implement fix-its reusing designated initializer computation from Clangd
1 parent 9c53c3c commit 42b9448

File tree

2 files changed

+44
-31
lines changed

2 files changed

+44
-31
lines changed

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

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
#include "clang/ASTMatchers/ASTMatchFinder.h"
1515
#include "clang/ASTMatchers/ASTMatchers.h"
1616
#include "clang/ASTMatchers/ASTMatchersMacros.h"
17-
#include <algorithm>
18-
#include <iterator>
19-
#include <vector>
17+
#include "clang/Basic/Diagnostic.h"
18+
#include "clang/Lex/Lexer.h"
19+
#include "clang/Tooling/DesignatedInitializers.h"
2020

2121
using namespace clang::ast_matchers;
2222

@@ -29,15 +29,6 @@ static const bool IgnoreSingleElementAggregatesDefault = true;
2929
static const char *RestrictToPODTypesName = "RestrictToPODTypes";
3030
static const bool RestrictToPODTypesDefault = false;
3131

32-
static std::vector<Stmt *>
33-
getUndesignatedComponents(const InitListExpr *SyntacticInitList) {
34-
std::vector<Stmt *> Result;
35-
std::copy_if(SyntacticInitList->begin(), SyntacticInitList->end(),
36-
std::back_inserter(Result),
37-
[](auto S) { return !isa<DesignatedInitExpr>(S); });
38-
return Result;
39-
}
40-
4132
UseDesignatedInitializersCheck::UseDesignatedInitializersCheck(
4233
StringRef Name, ClangTidyContext *Context)
4334
: ClangTidyCheck(Name, Context), IgnoreSingleElementAggregates(Options.get(
@@ -51,7 +42,9 @@ AST_MATCHER(CXXRecordDecl, isAggregate) { return Node.isAggregate(); }
5142
AST_MATCHER(CXXRecordDecl, isPOD) { return Node.isPOD(); }
5243

5344
AST_MATCHER(InitListExpr, isFullyDesignated) {
54-
return getUndesignatedComponents(&Node).empty();
45+
return std::all_of(Node.begin(), Node.end(), [](auto *InitExpr) {
46+
return isa<DesignatedInitExpr>(InitExpr);
47+
});
5548
}
5649

5750
AST_MATCHER(InitListExpr, hasSingleElement) { return Node.getNumInits() == 1; }
@@ -82,31 +75,43 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) {
8275
this);
8376
}
8477

78+
static bool isFullyUndesignated(const InitListExpr *SyntacticInitList) {
79+
return std::all_of(
80+
SyntacticInitList->begin(), SyntacticInitList->end(),
81+
[](auto *InitExpr) { return !isa<DesignatedInitExpr>(InitExpr); });
82+
}
83+
8584
void UseDesignatedInitializersCheck::check(
8685
const MatchFinder::MatchResult &Result) {
8786
const auto *InitList = Result.Nodes.getNodeAs<InitListExpr>("init");
8887
const auto *Type = Result.Nodes.getNodeAs<CXXRecordDecl>("type");
8988
if (!Type || !InitList)
9089
return;
9190
if (const auto *SyntacticInitList = InitList->getSyntacticForm()) {
92-
const auto UndesignatedComponents =
93-
getUndesignatedComponents(SyntacticInitList);
94-
if (UndesignatedComponents.size() == SyntacticInitList->getNumInits()) {
95-
diag(InitList->getLBraceLoc(), "use designated initializer list");
96-
return;
97-
}
98-
const auto FieldIterator = Type->fields().begin();
99-
for (const auto *InitExpr : *SyntacticInitList) {
100-
const auto Field = std::next(FieldIterator);
101-
if (std::find(UndesignatedComponents.begin(),
102-
UndesignatedComponents.end(),
103-
InitExpr) == UndesignatedComponents.end())
104-
continue;
105-
if (const auto *FieldID = Field->getIdentifier()) {
106-
const auto FieldName = FieldID->getName();
107-
diag(InitExpr->getBeginLoc(), "use designated init expression")
108-
<< FixItHint::CreateInsertion(InitExpr->getBeginLoc(),
109-
"." + FieldName.str() + "=");
91+
const llvm::DenseMap<clang::SourceLocation, std::string> Designators =
92+
clang::tooling::getDesignators(SyntacticInitList);
93+
if (isFullyUndesignated(SyntacticInitList)) {
94+
std::string NewList = "{";
95+
for (const Stmt *InitExpr : *SyntacticInitList) {
96+
if (InitExpr != *SyntacticInitList->begin())
97+
NewList += ", ";
98+
NewList += Designators.at(InitExpr->getBeginLoc());
99+
NewList += "=";
100+
NewList += Lexer::getSourceText(
101+
CharSourceRange::getTokenRange(InitExpr->getSourceRange()),
102+
*Result.SourceManager, getLangOpts());
103+
}
104+
NewList += "}";
105+
diag(InitList->getLBraceLoc(), "use designated initializer list")
106+
<< FixItHint::CreateReplacement(InitList->getSourceRange(), NewList);
107+
} else {
108+
for (const auto *InitExpr : *SyntacticInitList) {
109+
if (!isa<DesignatedInitExpr>(InitExpr)) {
110+
diag(InitExpr->getBeginLoc(), "use designated init expression")
111+
<< FixItHint::CreateInsertion(
112+
InitExpr->getBeginLoc(),
113+
Designators.at(InitExpr->getBeginLoc()) + "=");
114+
}
110115
}
111116
}
112117
}

clang-tools-extra/test/clang-tidy/checkers/modernize/use-designated-initializers.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,19 @@ S2 s21{.i=1, .j =2};
2020
S2 s22 = {1, 2};
2121
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
2222
// CHECK-MESSAGES-POD: :[[@LINE-2]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
23+
// CHECK-FIXES: S2 s22 = {.i=1, .j=2};
2324

2425
S2 s23{1};
2526
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
2627
// CHECK-MESSAGES-POD: :[[@LINE-2]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
28+
// CHECK-FIXES: S2 s23{.i=1};
2729

2830
S2 s24{.i = 1};
2931

3032
S2 s25 = {.i=1, 2};
3133
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use designated init expression [modernize-use-designated-initializers]
3234
// CHECK-MESSAGES-POD: :[[@LINE-2]]:17: warning: use designated init expression [modernize-use-designated-initializers]
35+
// CHECK-FIXES: S2 s25 = {.i=1, .j=2};
3336

3437
class S3 {
3538
public:
@@ -42,12 +45,14 @@ S3 s31 = {.s2 = 1, 2, 3.1};
4245
// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use designated init expression [modernize-use-designated-initializers]
4346
// CHECK-MESSAGES-POD: :[[@LINE-3]]:20: warning: use designated init expression [modernize-use-designated-initializers]
4447
// CHECK-MESSAGES-POD: :[[@LINE-4]]:23: warning: use designated init expression [modernize-use-designated-initializers]
48+
// CHECK-FIXES: S3 s31 = {.s2 = 1, .s2.j=2, .d=3.1};
4549

4650
S3 s32 = {{.i = 1, 2}};
4751
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
4852
// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: use designated init expression [modernize-use-designated-initializers]
4953
// CHECK-MESSAGES-POD: :[[@LINE-3]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
5054
// CHECK-MESSAGES-POD: :[[@LINE-4]]:20: warning: use designated init expression [modernize-use-designated-initializers]
55+
// CHECK-FIXES: S3 s32 = {.s2={.i = 1, 2}};
5156

5257
struct S4 {
5358
double d;
@@ -56,9 +61,11 @@ struct S4 {
5661

5762
S4 s41 {2.2};
5863
// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:8: warning: use designated initializer list [modernize-use-designated-initializers]
64+
// CHECK-FIXES-SINGLE-ELEMENT: S4 s41 {.d=2.2};
5965

6066
S4 s42 = {{}};
6167
// CHECK-MESSAGES-SINGLE-ELEMENT: :[[@LINE-1]]:10: warning: use designated initializer list [modernize-use-designated-initializers]
68+
// CHECK-FIXES-SINGLE-ELEMENT: S4 s42 = {.d={}};
6269

6370
template<typename S> S template1() { return {10, 11}; }
6471

@@ -99,3 +106,4 @@ struct S9 {
99106

100107
S9 s91{1, 2};
101108
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use designated initializer list [modernize-use-designated-initializers]
109+
// CHECK-FIXES: S9 s91{.i=1, .j=2};

0 commit comments

Comments
 (0)