Skip to content

Commit

Permalink
[clang-tidy] Add check 'modernize-return-braced-init-list'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
JDevlieghere committed Feb 15, 2017
1 parent 0ac6d12 commit 2789043
Show file tree
Hide file tree
Showing 8 changed files with 365 additions and 0 deletions.
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
Expand Up @@ -13,6 +13,7 @@ add_clang_library(clangTidyModernizeModule
RawStringLiteralCheck.cpp
RedundantVoidArgCheck.cpp
ReplaceAutoPtrCheck.cpp
ReturnBracedInitListCheck.cpp
ShrinkToFitCheck.cpp
UseAutoCheck.cpp
UseBoolLiteralsCheck.cpp
Expand Down
Expand Up @@ -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"
Expand Down Expand Up @@ -53,6 +54,8 @@ class ModernizeModule : public ClangTidyModule {
"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>(
Expand Down
@@ -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
36 changes: 36 additions & 0 deletions clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.h
@@ -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
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Expand Up @@ -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
-----------------------------

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Expand Up @@ -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
Expand Down
@@ -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 comments on commit 2789043

Please sign in to comment.