Skip to content

Commit 2789043

Browse files
committedFeb 15, 2017
[clang-tidy] Add check 'modernize-return-braced-init-list'
Summary: Replaces explicit calls to the constructor in a return with a braced initializer list. This way the return type is not needlessly duplicated in the return type and the return statement. ``` Foo bar() { Baz baz; return Foo(baz); } // transforms to: Foo bar() { Baz baz; return {baz}; } ``` Reviewers: hokein, Prazek, aaron.ballman, alexfh Reviewed By: Prazek, aaron.ballman, alexfh Subscribers: malcolm.parsons, mgorny, cfe-commits Tags: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D28768 llvm-svn: 295199
1 parent 0ac6d12 commit 2789043

File tree

8 files changed

+365
-0
lines changed

8 files changed

+365
-0
lines changed
 

‎clang-tools-extra/clang-tidy/modernize/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ add_clang_library(clangTidyModernizeModule
1313
RawStringLiteralCheck.cpp
1414
RedundantVoidArgCheck.cpp
1515
ReplaceAutoPtrCheck.cpp
16+
ReturnBracedInitListCheck.cpp
1617
ShrinkToFitCheck.cpp
1718
UseAutoCheck.cpp
1819
UseBoolLiteralsCheck.cpp

‎clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "RawStringLiteralCheck.h"
2020
#include "RedundantVoidArgCheck.h"
2121
#include "ReplaceAutoPtrCheck.h"
22+
#include "ReturnBracedInitListCheck.h"
2223
#include "ShrinkToFitCheck.h"
2324
#include "UseAutoCheck.h"
2425
#include "UseBoolLiteralsCheck.h"
@@ -53,6 +54,8 @@ class ModernizeModule : public ClangTidyModule {
5354
"modernize-redundant-void-arg");
5455
CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
5556
"modernize-replace-auto-ptr");
57+
CheckFactories.registerCheck<ReturnBracedInitListCheck>(
58+
"modernize-return-braced-init-list");
5659
CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
5760
CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
5861
CheckFactories.registerCheck<UseBoolLiteralsCheck>(
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//===--- ReturnBracedInitListCheck.cpp - clang-tidy------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "ReturnBracedInitListCheck.h"
11+
#include "clang/AST/ASTContext.h"
12+
#include "clang/ASTMatchers/ASTMatchFinder.h"
13+
#include "clang/Lex/Lexer.h"
14+
#include "clang/Tooling/FixIt.h"
15+
16+
using namespace clang::ast_matchers;
17+
18+
namespace clang {
19+
namespace tidy {
20+
namespace modernize {
21+
22+
void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
23+
// Only register the matchers for C++.
24+
if (!getLangOpts().CPlusPlus11)
25+
return;
26+
27+
// Skip list initialization and constructors with an initializer list.
28+
auto ConstructExpr =
29+
cxxConstructExpr(
30+
unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())),
31+
isListInitialization(), hasDescendant(initListExpr()),
32+
isInTemplateInstantiation())))
33+
.bind("ctor");
34+
35+
auto CtorAsArgument = materializeTemporaryExpr(anyOf(
36+
has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr)))));
37+
38+
Finder->addMatcher(
39+
functionDecl(isDefinition(), // Declarations don't have return statements.
40+
returns(unless(anyOf(builtinType(), autoType()))),
41+
hasDescendant(returnStmt(hasReturnValue(
42+
has(cxxConstructExpr(has(CtorAsArgument)))))))
43+
.bind("fn"),
44+
this);
45+
}
46+
47+
void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) {
48+
const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>("fn");
49+
const auto *MatchedConstructExpr =
50+
Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
51+
52+
// Don't make replacements in macro.
53+
SourceLocation Loc = MatchedConstructExpr->getExprLoc();
54+
if (Loc.isMacroID())
55+
return;
56+
57+
// Make sure that the return type matches the constructed type.
58+
const QualType ReturnType =
59+
MatchedFunctionDecl->getReturnType().getCanonicalType();
60+
const QualType ConstructType =
61+
MatchedConstructExpr->getType().getCanonicalType();
62+
if (ReturnType != ConstructType)
63+
return;
64+
65+
auto Diag = diag(Loc, "avoid repeating the return type from the "
66+
"declaration; use a braced initializer list instead");
67+
68+
const SourceRange CallParensRange =
69+
MatchedConstructExpr->getParenOrBraceRange();
70+
71+
// Make sure there is an explicit constructor call.
72+
if (CallParensRange.isInvalid())
73+
return;
74+
75+
// Make sure that the ctor arguments match the declaration.
76+
for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs();
77+
I < NumParams; ++I) {
78+
if (const auto *VD = dyn_cast<VarDecl>(
79+
MatchedConstructExpr->getConstructor()->getParamDecl(I))) {
80+
if (MatchedConstructExpr->getArg(I)->getType().getCanonicalType() !=
81+
VD->getType().getCanonicalType())
82+
return;
83+
}
84+
}
85+
86+
// Range for constructor name and opening brace.
87+
CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange(
88+
Loc, CallParensRange.getBegin().getLocWithOffset(-1));
89+
90+
Diag << FixItHint::CreateRemoval(CtorCallSourceRange)
91+
<< FixItHint::CreateReplacement(CallParensRange.getBegin(), "{")
92+
<< FixItHint::CreateReplacement(CallParensRange.getEnd(), "}");
93+
}
94+
95+
} // namespace modernize
96+
} // namespace tidy
97+
} // namespace clang
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===--- ReturnBracedInitListCheck.h - clang-tidy----------------*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
11+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
12+
13+
#include "../ClangTidy.h"
14+
15+
namespace clang {
16+
namespace tidy {
17+
namespace modernize {
18+
19+
/// Use a braced init list for return statements rather than unnecessary
20+
/// repeating the return type name.
21+
///
22+
/// For the user-facing documentation see:
23+
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-return-braced-init-list.html
24+
class ReturnBracedInitListCheck : public ClangTidyCheck {
25+
public:
26+
ReturnBracedInitListCheck(StringRef Name, ClangTidyContext *Context)
27+
: ClangTidyCheck(Name, Context) {}
28+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
29+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
30+
};
31+
32+
} // namespace modernize
33+
} // namespace tidy
34+
} // namespace clang
35+
36+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H

‎clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ Improvements to clang-tidy
6767

6868
Finds uses of inline assembler.
6969

70+
- New `modernize-return-braced-init-list
71+
<http://clang.llvm.org/extra/clang-tidy/checks/modernize-return-braced-init-list.html>`_ check
72+
73+
Finds and replaces explicit calls to the constructor in a return statement by
74+
a braced initializer list so that the return type is not needlessly repeated.
75+
7076
Improvements to include-fixer
7177
-----------------------------
7278

‎clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ Clang-Tidy Checks
109109
modernize-raw-string-literal
110110
modernize-redundant-void-arg
111111
modernize-replace-auto-ptr
112+
modernize-return-braced-init-list
112113
modernize-shrink-to-fit
113114
modernize-use-auto
114115
modernize-use-bool-literals
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.. title:: clang-tidy - modernize-return-braced-init-list
2+
3+
modernize-return-braced-init-list
4+
=================================
5+
6+
Replaces explicit calls to the constructor in a return with a braced
7+
initializer list. This way the return type is not needlessly duplicated in the
8+
function definition and the return statement.
9+
10+
.. code:: c++
11+
12+
Foo bar() {
13+
Baz baz;
14+
return Foo(baz);
15+
}
16+
17+
// transforms to:
18+
19+
Foo bar() {
20+
Baz baz;
21+
return {baz};
22+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// RUN: %check_clang_tidy %s modernize-return-braced-init-list %t -- --
2+
// -std=c++14
3+
4+
namespace std {
5+
typedef decltype(sizeof(int)) size_t;
6+
7+
// libc++'s implementation
8+
template <class _E>
9+
class initializer_list {
10+
const _E *__begin_;
11+
size_t __size_;
12+
13+
initializer_list(const _E *__b, size_t __s)
14+
: __begin_(__b),
15+
__size_(__s) {}
16+
17+
public:
18+
typedef _E value_type;
19+
typedef const _E &reference;
20+
typedef const _E &const_reference;
21+
typedef size_t size_type;
22+
23+
typedef const _E *iterator;
24+
typedef const _E *const_iterator;
25+
26+
initializer_list() : __begin_(nullptr), __size_(0) {}
27+
28+
size_t size() const { return __size_; }
29+
const _E *begin() const { return __begin_; }
30+
const _E *end() const { return __begin_ + __size_; }
31+
};
32+
33+
template <typename T>
34+
class vector {
35+
public:
36+
vector(T) {}
37+
vector(std::initializer_list<T>) {}
38+
};
39+
}
40+
41+
class Bar {};
42+
43+
Bar b0;
44+
45+
class Foo {
46+
public:
47+
Foo(Bar) {}
48+
explicit Foo(Bar, unsigned int) {}
49+
Foo(unsigned int) {}
50+
};
51+
52+
class Baz {
53+
public:
54+
Foo m() {
55+
Bar bm;
56+
return Foo(bm);
57+
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: avoid repeating the return type from the declaration; use a braced initializer list instead [modernize-return-braced-init-list]
58+
// CHECK-FIXES: return {bm};
59+
}
60+
};
61+
62+
class Quux : public Foo {
63+
public:
64+
Quux(Bar bar) : Foo(bar) {}
65+
Quux(unsigned, unsigned, unsigned k = 0) : Foo(k) {}
66+
};
67+
68+
Foo f() {
69+
Bar b1;
70+
return Foo(b1);
71+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
72+
// CHECK-FIXES: return {b1};
73+
}
74+
75+
Foo f2() {
76+
Bar b2;
77+
return {b2};
78+
}
79+
80+
auto f3() {
81+
Bar b3;
82+
return Foo(b3);
83+
}
84+
85+
#define A(b) Foo(b)
86+
87+
Foo f4() {
88+
Bar b4;
89+
return A(b4);
90+
}
91+
92+
Foo f5() {
93+
Bar b5;
94+
return Quux(b5);
95+
}
96+
97+
Foo f6() {
98+
Bar b6;
99+
return Foo(b6, 1);
100+
}
101+
102+
std::vector<int> f7() {
103+
int i7 = 1;
104+
return std::vector<int>(i7);
105+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
106+
}
107+
108+
Bar f8() {
109+
return {};
110+
}
111+
112+
Bar f9() {
113+
return Bar();
114+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
115+
}
116+
117+
Bar f10() {
118+
return Bar{};
119+
}
120+
121+
Foo f11(Bar b11) {
122+
return Foo(b11);
123+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
124+
// CHECK-FIXES: return {b11};
125+
}
126+
127+
Foo f12() {
128+
return f11(Bar());
129+
}
130+
131+
Foo f13() {
132+
return Foo(Bar()); // 13
133+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
134+
// CHECK-FIXES: return {Bar()}; // 13
135+
}
136+
137+
Foo f14() {
138+
// FIXME: Type narrowing should not occur!
139+
return Foo(-1);
140+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
141+
// CHECK-FIXES: return {-1};
142+
}
143+
144+
Foo f15() {
145+
return Foo(f10());
146+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
147+
// CHECK-FIXES: return {f10()};
148+
}
149+
150+
Quux f16() {
151+
return Quux(1, 2);
152+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
153+
// CHECK-FIXES: return {1, 2};
154+
}
155+
156+
Quux f17() {
157+
return Quux(1, 2, 3);
158+
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
159+
// CHECK-FIXES: return {1, 2, 3};
160+
}
161+
162+
template <typename T>
163+
T f19() {
164+
return T();
165+
}
166+
167+
Bar i1 = f19<Bar>();
168+
Baz i2 = f19<Baz>();
169+
170+
template <typename T>
171+
Foo f20(T t) {
172+
return Foo(t);
173+
}
174+
175+
Foo i3 = f20(b0);
176+
177+
template <typename T>
178+
class BazT {
179+
public:
180+
T m() {
181+
Bar b;
182+
return T(b);
183+
}
184+
185+
Foo m2(T t) {
186+
return Foo(t);
187+
}
188+
};
189+
190+
BazT<Foo> bazFoo;
191+
Foo i4 = bazFoo.m();
192+
Foo i5 = bazFoo.m2(b0);
193+
194+
BazT<Quux> bazQuux;
195+
Foo i6 = bazQuux.m();
196+
Foo i7 = bazQuux.m2(b0);
197+
198+
auto v1 = []() { return std::vector<int>({1, 2}); }();
199+
auto v2 = []() -> std::vector<int> { return std::vector<int>({1, 2}); }();

0 commit comments

Comments
 (0)
Please sign in to comment.