forked from OSchip/llvm-project
[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
This commit is contained in:
parent
0ac6d124cf
commit
2789043178
|
@ -13,6 +13,7 @@ add_clang_library(clangTidyModernizeModule
|
|||
RawStringLiteralCheck.cpp
|
||||
RedundantVoidArgCheck.cpp
|
||||
ReplaceAutoPtrCheck.cpp
|
||||
ReturnBracedInitListCheck.cpp
|
||||
ShrinkToFitCheck.cpp
|
||||
UseAutoCheck.cpp
|
||||
UseBoolLiteralsCheck.cpp
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "RawStringLiteralCheck.h"
|
||||
#include "RedundantVoidArgCheck.h"
|
||||
#include "ReplaceAutoPtrCheck.h"
|
||||
#include "ReturnBracedInitListCheck.h"
|
||||
#include "ShrinkToFitCheck.h"
|
||||
#include "UseAutoCheck.h"
|
||||
#include "UseBoolLiteralsCheck.h"
|
||||
|
@ -53,6 +54,8 @@ public:
|
|||
"modernize-redundant-void-arg");
|
||||
CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
|
||||
"modernize-replace-auto-ptr");
|
||||
CheckFactories.registerCheck<ReturnBracedInitListCheck>(
|
||||
"modernize-return-braced-init-list");
|
||||
CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
|
||||
CheckFactories.registerCheck<UseAutoCheck>("modernize-use-auto");
|
||||
CheckFactories.registerCheck<UseBoolLiteralsCheck>(
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
//===--- ReturnBracedInitListCheck.cpp - clang-tidy------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReturnBracedInitListCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Tooling/FixIt.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace modernize {
|
||||
|
||||
void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// Only register the matchers for C++.
|
||||
if (!getLangOpts().CPlusPlus11)
|
||||
return;
|
||||
|
||||
// Skip list initialization and constructors with an initializer list.
|
||||
auto ConstructExpr =
|
||||
cxxConstructExpr(
|
||||
unless(anyOf(hasDeclaration(cxxConstructorDecl(isExplicit())),
|
||||
isListInitialization(), hasDescendant(initListExpr()),
|
||||
isInTemplateInstantiation())))
|
||||
.bind("ctor");
|
||||
|
||||
auto CtorAsArgument = materializeTemporaryExpr(anyOf(
|
||||
has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr)))));
|
||||
|
||||
Finder->addMatcher(
|
||||
functionDecl(isDefinition(), // Declarations don't have return statements.
|
||||
returns(unless(anyOf(builtinType(), autoType()))),
|
||||
hasDescendant(returnStmt(hasReturnValue(
|
||||
has(cxxConstructExpr(has(CtorAsArgument)))))))
|
||||
.bind("fn"),
|
||||
this);
|
||||
}
|
||||
|
||||
void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs<FunctionDecl>("fn");
|
||||
const auto *MatchedConstructExpr =
|
||||
Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
|
||||
|
||||
// Don't make replacements in macro.
|
||||
SourceLocation Loc = MatchedConstructExpr->getExprLoc();
|
||||
if (Loc.isMacroID())
|
||||
return;
|
||||
|
||||
// Make sure that the return type matches the constructed type.
|
||||
const QualType ReturnType =
|
||||
MatchedFunctionDecl->getReturnType().getCanonicalType();
|
||||
const QualType ConstructType =
|
||||
MatchedConstructExpr->getType().getCanonicalType();
|
||||
if (ReturnType != ConstructType)
|
||||
return;
|
||||
|
||||
auto Diag = diag(Loc, "avoid repeating the return type from the "
|
||||
"declaration; use a braced initializer list instead");
|
||||
|
||||
const SourceRange CallParensRange =
|
||||
MatchedConstructExpr->getParenOrBraceRange();
|
||||
|
||||
// Make sure there is an explicit constructor call.
|
||||
if (CallParensRange.isInvalid())
|
||||
return;
|
||||
|
||||
// Make sure that the ctor arguments match the declaration.
|
||||
for (unsigned I = 0, NumParams = MatchedConstructExpr->getNumArgs();
|
||||
I < NumParams; ++I) {
|
||||
if (const auto *VD = dyn_cast<VarDecl>(
|
||||
MatchedConstructExpr->getConstructor()->getParamDecl(I))) {
|
||||
if (MatchedConstructExpr->getArg(I)->getType().getCanonicalType() !=
|
||||
VD->getType().getCanonicalType())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Range for constructor name and opening brace.
|
||||
CharSourceRange CtorCallSourceRange = CharSourceRange::getTokenRange(
|
||||
Loc, CallParensRange.getBegin().getLocWithOffset(-1));
|
||||
|
||||
Diag << FixItHint::CreateRemoval(CtorCallSourceRange)
|
||||
<< FixItHint::CreateReplacement(CallParensRange.getBegin(), "{")
|
||||
<< FixItHint::CreateReplacement(CallParensRange.getEnd(), "}");
|
||||
}
|
||||
|
||||
} // namespace modernize
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -0,0 +1,36 @@
|
|||
//===--- ReturnBracedInitListCheck.h - clang-tidy----------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace modernize {
|
||||
|
||||
/// Use a braced init list for return statements rather than unnecessary
|
||||
/// repeating the return type name.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-return-braced-init-list.html
|
||||
class ReturnBracedInitListCheck : public ClangTidyCheck {
|
||||
public:
|
||||
ReturnBracedInitListCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
} // namespace modernize
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_RETURN_BRACED_INIT_LIST_H
|
|
@ -67,6 +67,12 @@ Improvements to clang-tidy
|
|||
|
||||
Finds uses of inline assembler.
|
||||
|
||||
- New `modernize-return-braced-init-list
|
||||
<http://clang.llvm.org/extra/clang-tidy/checks/modernize-return-braced-init-list.html>`_ check
|
||||
|
||||
Finds and replaces explicit calls to the constructor in a return statement by
|
||||
a braced initializer list so that the return type is not needlessly repeated.
|
||||
|
||||
Improvements to include-fixer
|
||||
-----------------------------
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ Clang-Tidy Checks
|
|||
modernize-raw-string-literal
|
||||
modernize-redundant-void-arg
|
||||
modernize-replace-auto-ptr
|
||||
modernize-return-braced-init-list
|
||||
modernize-shrink-to-fit
|
||||
modernize-use-auto
|
||||
modernize-use-bool-literals
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
.. title:: clang-tidy - modernize-return-braced-init-list
|
||||
|
||||
modernize-return-braced-init-list
|
||||
=================================
|
||||
|
||||
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
|
||||
function definition and the return statement.
|
||||
|
||||
.. code:: c++
|
||||
|
||||
Foo bar() {
|
||||
Baz baz;
|
||||
return Foo(baz);
|
||||
}
|
||||
|
||||
// transforms to:
|
||||
|
||||
Foo bar() {
|
||||
Baz baz;
|
||||
return {baz};
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
// RUN: %check_clang_tidy %s modernize-return-braced-init-list %t -- --
|
||||
// -std=c++14
|
||||
|
||||
namespace std {
|
||||
typedef decltype(sizeof(int)) size_t;
|
||||
|
||||
// libc++'s implementation
|
||||
template <class _E>
|
||||
class initializer_list {
|
||||
const _E *__begin_;
|
||||
size_t __size_;
|
||||
|
||||
initializer_list(const _E *__b, size_t __s)
|
||||
: __begin_(__b),
|
||||
__size_(__s) {}
|
||||
|
||||
public:
|
||||
typedef _E value_type;
|
||||
typedef const _E &reference;
|
||||
typedef const _E &const_reference;
|
||||
typedef size_t size_type;
|
||||
|
||||
typedef const _E *iterator;
|
||||
typedef const _E *const_iterator;
|
||||
|
||||
initializer_list() : __begin_(nullptr), __size_(0) {}
|
||||
|
||||
size_t size() const { return __size_; }
|
||||
const _E *begin() const { return __begin_; }
|
||||
const _E *end() const { return __begin_ + __size_; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class vector {
|
||||
public:
|
||||
vector(T) {}
|
||||
vector(std::initializer_list<T>) {}
|
||||
};
|
||||
}
|
||||
|
||||
class Bar {};
|
||||
|
||||
Bar b0;
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
Foo(Bar) {}
|
||||
explicit Foo(Bar, unsigned int) {}
|
||||
Foo(unsigned int) {}
|
||||
};
|
||||
|
||||
class Baz {
|
||||
public:
|
||||
Foo m() {
|
||||
Bar bm;
|
||||
return Foo(bm);
|
||||
// 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]
|
||||
// CHECK-FIXES: return {bm};
|
||||
}
|
||||
};
|
||||
|
||||
class Quux : public Foo {
|
||||
public:
|
||||
Quux(Bar bar) : Foo(bar) {}
|
||||
Quux(unsigned, unsigned, unsigned k = 0) : Foo(k) {}
|
||||
};
|
||||
|
||||
Foo f() {
|
||||
Bar b1;
|
||||
return Foo(b1);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {b1};
|
||||
}
|
||||
|
||||
Foo f2() {
|
||||
Bar b2;
|
||||
return {b2};
|
||||
}
|
||||
|
||||
auto f3() {
|
||||
Bar b3;
|
||||
return Foo(b3);
|
||||
}
|
||||
|
||||
#define A(b) Foo(b)
|
||||
|
||||
Foo f4() {
|
||||
Bar b4;
|
||||
return A(b4);
|
||||
}
|
||||
|
||||
Foo f5() {
|
||||
Bar b5;
|
||||
return Quux(b5);
|
||||
}
|
||||
|
||||
Foo f6() {
|
||||
Bar b6;
|
||||
return Foo(b6, 1);
|
||||
}
|
||||
|
||||
std::vector<int> f7() {
|
||||
int i7 = 1;
|
||||
return std::vector<int>(i7);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
}
|
||||
|
||||
Bar f8() {
|
||||
return {};
|
||||
}
|
||||
|
||||
Bar f9() {
|
||||
return Bar();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
}
|
||||
|
||||
Bar f10() {
|
||||
return Bar{};
|
||||
}
|
||||
|
||||
Foo f11(Bar b11) {
|
||||
return Foo(b11);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {b11};
|
||||
}
|
||||
|
||||
Foo f12() {
|
||||
return f11(Bar());
|
||||
}
|
||||
|
||||
Foo f13() {
|
||||
return Foo(Bar()); // 13
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {Bar()}; // 13
|
||||
}
|
||||
|
||||
Foo f14() {
|
||||
// FIXME: Type narrowing should not occur!
|
||||
return Foo(-1);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {-1};
|
||||
}
|
||||
|
||||
Foo f15() {
|
||||
return Foo(f10());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {f10()};
|
||||
}
|
||||
|
||||
Quux f16() {
|
||||
return Quux(1, 2);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {1, 2};
|
||||
}
|
||||
|
||||
Quux f17() {
|
||||
return Quux(1, 2, 3);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: avoid repeating the return type
|
||||
// CHECK-FIXES: return {1, 2, 3};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T f19() {
|
||||
return T();
|
||||
}
|
||||
|
||||
Bar i1 = f19<Bar>();
|
||||
Baz i2 = f19<Baz>();
|
||||
|
||||
template <typename T>
|
||||
Foo f20(T t) {
|
||||
return Foo(t);
|
||||
}
|
||||
|
||||
Foo i3 = f20(b0);
|
||||
|
||||
template <typename T>
|
||||
class BazT {
|
||||
public:
|
||||
T m() {
|
||||
Bar b;
|
||||
return T(b);
|
||||
}
|
||||
|
||||
Foo m2(T t) {
|
||||
return Foo(t);
|
||||
}
|
||||
};
|
||||
|
||||
BazT<Foo> bazFoo;
|
||||
Foo i4 = bazFoo.m();
|
||||
Foo i5 = bazFoo.m2(b0);
|
||||
|
||||
BazT<Quux> bazQuux;
|
||||
Foo i6 = bazQuux.m();
|
||||
Foo i7 = bazQuux.m2(b0);
|
||||
|
||||
auto v1 = []() { return std::vector<int>({1, 2}); }();
|
||||
auto v2 = []() -> std::vector<int> { return std::vector<int>({1, 2}); }();
|
Loading…
Reference in New Issue