Index: clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tidy/modernize/CMakeLists.txt +++ clang-tidy/modernize/CMakeLists.txt @@ -13,6 +13,7 @@ RawStringLiteralCheck.cpp RedundantVoidArgCheck.cpp ReplaceAutoPtrCheck.cpp + ReturnBracedInitListCheck.cpp ShrinkToFitCheck.cpp UseAutoCheck.cpp UseBoolLiteralsCheck.cpp Index: clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tidy/modernize/ModernizeTidyModule.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 @@ "modernize-redundant-void-arg"); CheckFactories.registerCheck( "modernize-replace-auto-ptr"); + CheckFactories.registerCheck( + "modernize-return-braced-init-list"); CheckFactories.registerCheck("modernize-shrink-to-fit"); CheckFactories.registerCheck("modernize-use-auto"); CheckFactories.registerCheck( Index: clang-tidy/modernize/ReturnBracedInitListCheck.h =================================================================== --- /dev/null +++ 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 Index: clang-tidy/modernize/ReturnBracedInitListCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/modernize/ReturnBracedInitListCheck.cpp @@ -0,0 +1,81 @@ +//===--- 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; + + auto soughtConstructExpr = + cxxConstructExpr(unless(isListInitialization())).bind("ctor"); + + auto hasConstructExpr = has(ignoringImplicit(soughtConstructExpr)); + + auto ctorAsArgument = materializeTemporaryExpr( + anyOf(hasConstructExpr, has(cxxFunctionalCastExpr(hasConstructExpr)))); + + Finder->addMatcher( + functionDecl(isDefinition(), // Declarations don't have return statements. + returns(recordType()), // We only care about record types. + hasDescendant(returnStmt(hasDescendant(ctorAsArgument)))) + .bind("fn"), + this); +} + +void ReturnBracedInitListCheck::check(const MatchFinder::MatchResult &Result) { + const auto *MatchedFunctionDecl = Result.Nodes.getNodeAs("fn"); + const auto *MatchedConstructExpr = + Result.Nodes.getNodeAs("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(); + const QualType constructType = MatchedConstructExpr->getType(); + if (returnType != constructType) + return; + + auto Diag = + diag(Loc, "use braced initializer list for constructing return types"); + + auto CallParensRange = MatchedConstructExpr->getParenOrBraceRange(); + + // Return if there is no explicit constructor call. + if (CallParensRange.isInvalid()) + return; + + Diag << FixItHint::CreateRemoval(MatchedConstructExpr->getLocStart()); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(CallParensRange.getBegin(), + CallParensRange.getBegin()), + "{"); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(CallParensRange.getEnd(), + CallParensRange.getEnd()), + "}"); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,7 +57,11 @@ Improvements to clang-tidy -------------------------- -The improvements are... +- New `modernize-return-braced-init-list + `_ check + + 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 ----------------------------- Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -109,6 +109,7 @@ 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 Index: docs/clang-tidy/checks/modernize-return-braced-init-list.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/modernize-return-braced-init-list.rst @@ -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 +return type and the return statement. + +.. code:: c++ + + Foo bar() { + Baz baz; + return Foo(baz); + } + + // transforms to: + + Foo bar() { + Baz baz; + return {baz}; + } Index: test/clang-tidy/modernize-return-braced-init-list.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-return-braced-init-list.cpp @@ -0,0 +1,38 @@ +// RUN: %check_clang_tidy %s modernize-return-braced-init-list %t -- -- -std=c++14 + +class Bar {}; + +class Foo { +public: + Foo(Bar bar) : bar(bar){}; + +private: + Bar bar; +}; + +class Baz { +public: + Foo m() { + Bar b; + return Foo(b); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use braced initializer list for constructing return types [modernize-return-braced-init-list] + // CHECK-FIXES: return {b}; + } +}; + +Foo f() { + Bar b; + return Foo(b); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use braced initializer list for constructing return types [modernize-return-braced-init-list] + // CHECK-FIXES: return {b}; +} + +Foo f2() { + Bar b; + return {b}; +} + +auto f3() { + Bar b; + return Foo(b); +}