bernhardmgruber updated this revision to Diff 179945.
bernhardmgruber marked 2 inline comments as done.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D56160/new/
https://reviews.llvm.org/D56160
Files:
clang-tidy/modernize/CMakeLists.txt
clang-tidy/modernize/ModernizeTidyModule.cpp
clang-tidy/modernize/UseTrailingReturnCheck.cpp
clang-tidy/modernize/UseTrailingReturnCheck.h
docs/clang-tidy/checks/modernize-use-trailing-return.rst
test/clang-tidy/modernize-use-trailing-return.cpp
Index: test/clang-tidy/modernize-use-trailing-return.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/modernize-use-trailing-return.cpp
@@ -0,0 +1,144 @@
+// RUN: %check_clang_tidy %s modernize-use-trailing-return %t -- -- --std=c++14
+
+namespace std {
+ template <typename T>
+ class vector;
+
+ class string;
+}
+
+//
+// Samples triggering the check
+//
+
+int f();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto f() -> int;{{$}}
+int f(int);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto f(int) -> int;{{$}}
+int f(int arg);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto f(int arg) -> int;{{$}}
+int f(int arg1, int arg2, int arg3);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto f(int arg1, int arg2, int arg3) -> int;{{$}}
+int f(int arg1, int arg2, int arg3, ...);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto f(int arg1, int arg2, int arg3, ...) -> int;{{$}}
+template <typename T> int f(T t);
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}template <typename T> auto f(T t) -> int;{{$}}
+int a1() { return 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto a1() -> int { return 42; }{{$}}
+int a2() {
+ return 42;
+}
+// CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto a2() -> int {{{$}}
+int a3()
+{
+ return 42;
+}
+// CHECK-MESSAGES: :[[@LINE-4]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto a3() -> int{{$}}
+int b(int arg ) ;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto b(int arg ) -> int ;{{$}}
+inline int d1(int arg);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}inline auto d1(int arg) -> int;{{$}}
+inline int d2(int arg) noexcept(true);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}inline auto d2(int arg) -> int noexcept(true);{{$}}
+inline int d3(int arg) try { } catch(...) { }
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}inline auto d3(int arg) -> int try { } catch(...) { }{{$}}
+namespace N {
+ bool e1();
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:10: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} auto e1() -> bool;{{$}}
+inline volatile const std::vector<std::string> e2();
+// CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}inline auto e2() -> volatile const std::vector<std::string>;{{$}}
+inline const std::vector<std::string> volatile e2();
+// CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}inline auto e2() -> const std::vector<std::string> volatile;{{$}}
+inline std::vector<std::string> const volatile e2();
+// CHECK-MESSAGES: :[[@LINE-1]]:48: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}inline auto e2() -> std::vector<std::string> const volatile;{{$}}
+bool N::e1() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto N::e1() -> bool {}{{$}}
+int (*e3())(double);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use a trailing return type for this function (FixIt not implemented) [modernize-use-trailing-return]
+// TODO: not matched by the AST matcher
+//decltype(auto) e4();
+// _HECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// _HECK-FIXES: {{^}}auto e4() -> decltype(auto);{{$}}
+
+struct B {
+ double base1(int, bool b);
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} auto base1(int, bool b) -> double;{{$}}
+
+ virtual double base2(int, bool b) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} virtual auto base2(int, bool b) -> double {}{{$}}
+
+ virtual float base3() const = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} virtual auto base3() const -> float = 0;{{$}}
+
+ double base4(int, bool b) &&;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} auto base4(int, bool b) && -> double;{{$}}
+
+ double base5(int, bool b) const &&;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} auto base5(int, bool b) const && -> double;{{$}}
+
+ double base6(int, bool b) const & = delete;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} auto base6(int, bool b) const & -> double = delete;{{$}}
+};
+
+struct D : B {
+ virtual double f1(int, bool b) final;
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} virtual auto f1(int, bool b) -> double final;{{$}}
+
+ virtual double base2(int, bool b) override;
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} virtual auto base2(int, bool b) -> double override;{{$}}
+
+ virtual float base3() const override final { }
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}} virtual auto base3() const -> float override final { }{{$}}
+};
+
+//
+// Samples which do not trigger the check
+//
+
+auto ff();
+auto f() -> int;
+auto f(int) -> int;
+auto f(int arg) -> int;
+auto f(int arg1, int arg2, int arg3) -> int;
+auto f(int arg1, int arg2, int arg3, ...) -> int;
+template <typename T> auto f(T t) -> int;
+
+void c();
+void c(int arg);
+void c(int arg) { return; }
+
+struct D2 : B {
+ virtual auto f1(int, bool b) -> double final;
+ virtual auto base2(int, bool b) -> double override;
+ virtual auto base3() const -> float override final { }
+
+ operator double();
+};
Index: docs/clang-tidy/checks/modernize-use-trailing-return.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/modernize-use-trailing-return.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - modernize-use-trailing-return
+
+modernize-use-trailing-return
+=============================
+
+Rewrites function signatures to use a trailing return type
+(introduced in C++11). This transformation is purely stylistic.
+The return type before the function name is replaced by ``auto``
+and inserted after the function parameter list (and qualifiers).
+
+Example
+-------
+
+.. code-block:: c++
+
+ int f1();
+ inline int f2(int arg) noexcept;
+ virtual float f3() const && = delete;
+
+transforms to:
+
+.. code-block:: c++
+
+ auto f1() -> int;
+ inline auto f2(int arg) -> int noexcept;
+ virtual auto f3() const && -> float = delete;
Index: clang-tidy/modernize/UseTrailingReturnCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseTrailingReturnCheck.h
@@ -0,0 +1,35 @@
+//===--- UseTrailingReturnCheck.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_USETRAILINGRETURNCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USETRAILINGRETURNCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Rewrites function signatures to use a trailing return type.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-trailing-return.html
+class UseTrailingReturnCheck : public ClangTidyCheck {
+public:
+ UseTrailingReturnCheck(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_USETRAILINGRETURNCHECK_H
Index: clang-tidy/modernize/UseTrailingReturnCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseTrailingReturnCheck.cpp
@@ -0,0 +1,207 @@
+//===--- UseTrailingReturnCheck.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 "UseTrailingReturnCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+// very similar to UseOverrideCheck
+static SourceLocation findTrailingReturnTypeSourceLocation(
+ const CharSourceRange &Range, const ASTContext &Ctx,
+ const SourceManager &SM, const LangOptions &LangOpts) {
+ const std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(Range.getBegin());
+ const StringRef File = SM.getBufferData(Loc.first);
+ const char *TokenBegin = File.data() + Loc.second;
+ Lexer Lexer(SM.getLocForStartOfFile(Loc.first), LangOpts, File.begin(),
+ TokenBegin, File.end());
+ Token T;
+ int NestedParens = 0;
+ SourceLocation Result;
+ while (!Lexer.LexFromRawLexer(T)) {
+ if (SM.isBeforeInTranslationUnit(Range.getEnd(), T.getLocation()))
+ break;
+ if (Result.isValid()) {
+ // we found the closing parenthesis, skip additional const and ref
+ // qualifiers
+
+ if (T.is(tok::amp) || T.is(tok::ampamp)) {
+ Result = T.getEndLoc();
+ continue;
+ }
+
+ if (T.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = Ctx.Idents.get(
+ StringRef(SM.getCharacterData(T.getLocation()), T.getLength()));
+ T.setIdentifierInfo(&Info);
+ T.setKind(Info.getTokenID());
+ }
+
+ if (T.is(tok::kw_const)) {
+ Result = T.getEndLoc();
+ continue;
+ }
+
+ return Result;
+ }
+ if (T.is(tok::l_paren))
+ ++NestedParens;
+ else if (T.is(tok::r_paren)) {
+ --NestedParens;
+ if (NestedParens == 0)
+ Result = T.getEndLoc(); // store location, next token might be const
+ }
+ }
+
+ if (Result.isValid())
+ return Result;
+
+ llvm_unreachable("Expected to find a closing parenthesis");
+}
+
+static SourceRange findReturnTypeAndCVSourceRange(const FunctionDecl &F,
+ const ASTContext &Ctx,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+
+ // we start with the range of the return type and expand to neighboring const
+ // and volatile
+ SourceRange ReturnTypeRange = F.getReturnTypeSourceRange();
+
+ // create tokens for everything before the name of the function
+ const std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(F.getBeginLoc());
+ const StringRef File = SM.getBufferData(Loc.first);
+ const char *TokenBegin = File.data() + Loc.second;
+ Lexer Lexer(SM.getLocForStartOfFile(Loc.first), LangOpts, File.begin(),
+ TokenBegin, File.end());
+ Token T;
+ SmallVector<Token, 8> Tokens;
+ while (!Lexer.LexFromRawLexer(T)) {
+ if (SM.isBeforeInTranslationUnit(F.getLocation(), T.getLocation()))
+ break;
+ if (T.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = Ctx.Idents.get(
+ StringRef(SM.getCharacterData(T.getLocation()), T.getLength()));
+ T.setIdentifierInfo(&Info);
+ T.setKind(Info.getTokenID());
+ }
+ Tokens.push_back(T);
+ }
+
+ // include const and volatile to the left and right of the return type
+ auto IsCV = [](Token T) {
+ return T.is(tok::kw_const) || T.is(tok::kw_volatile);
+ };
+
+ bool ExtendedLeft = false;
+ for (int i = 0; i < Tokens.size(); i++) {
+ // if we found the beginning of the return type, include const and volatile
+ // to the left
+ if (!SM.isBeforeInTranslationUnit(Tokens[i].getLocation(),
+ ReturnTypeRange.getBegin()) &&
+ !ExtendedLeft) {
+ for (int j = i - 1; j >= 0 && IsCV(Tokens[j]); j--)
+ ReturnTypeRange.setBegin(Tokens[j].getLocation());
+ ExtendedLeft = true;
+ }
+ // if we found the end of the return type, include const and volatile to the
+ // right
+ if (SM.isBeforeInTranslationUnit(ReturnTypeRange.getEnd(),
+ Tokens[i].getLocation())) {
+ for (int j = i; j < Tokens.size() && IsCV(Tokens[j]); j++)
+ ReturnTypeRange.setEnd(Tokens[j].getLocation());
+ break;
+ }
+ }
+
+ return ReturnTypeRange;
+}
+
+void UseTrailingReturnCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+
+ Finder->addMatcher(
+ functionDecl(unless(anyOf(hasTrailingReturn(), returns(voidType()),
+ returns(autoType()), cxxConversionDecl())))
+ .bind("f"),
+ this);
+}
+
+void UseTrailingReturnCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *F = Result.Nodes.getNodeAs<FunctionDecl>("f");
+ if (!F)
+ return;
+
+ if (const auto *M = dyn_cast<CXXMethodDecl>(F))
+ if (M->isImplicit() || M->getLocation().isMacroID() || M->isOutOfLine())
+ return;
+
+ if (F->getDeclaredReturnType()->isFunctionPointerType()) {
+ diag(
+ F->getLocation(),
+ "use a trailing return type for this function (FixIt not implemented)");
+ return;
+ }
+
+ const auto &Ctx = *Result.Context;
+ const auto &SM = *Result.SourceManager;
+ const auto &LangOpts = getLangOpts();
+
+ SourceRange ReturnTypeCVRange = findReturnTypeAndCVSourceRange(*F, Ctx, SM, LangOpts);
+ if (!ReturnTypeCVRange.isValid()) {
+ diag(F->getLocation(),
+ "use a trailing return type for this function (failed to determine "
+ "return type source range, could clang resolve all #includes?)",
+ DiagnosticIDs::Level::Error);
+ return;
+ }
+
+ const CharSourceRange CharRange = Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(F->getSourceRange()), SM, LangOpts);
+ if (!CharRange.isValid())
+ return;
+ const SourceLocation InsertionLoc =
+ findTrailingReturnTypeSourceLocation(CharRange, Ctx, SM, LangOpts);
+
+ // extract return type as string
+ const std::string ReturnType = [&] {
+ // using the declared return type via
+ // F->getDeclaredReturnType().getAsString() discards user formatting and
+ // order (order of const, volatile, type, whitespace, space before & ...)
+
+ const std::pair<FileID, unsigned> Beg =
+ SM.getDecomposedLoc(ReturnTypeCVRange.getBegin());
+ const StringRef File = SM.getBufferData(Beg.first);
+ const char *BegPtr = File.data() + Beg.second;
+
+ const std::pair<FileID, unsigned> End =
+ SM.getDecomposedLoc(Lexer::getLocForEndOfToken(
+ ReturnTypeCVRange.getEnd(), 0, SM, LangOpts));
+ assert(Beg.first == End.first);
+ assert(Beg.second != End.second);
+ const char *EndPtr = File.data() + End.second;
+
+ return std::string(BegPtr, EndPtr);
+ }();
+
+ auto D =
+ diag(F->getLocation(), "use a trailing return type for this function");
+ D << FixItHint::CreateReplacement(ReturnTypeCVRange, "auto");
+ D << FixItHint::CreateInsertion(InsertionLoc, " -> " + ReturnType);
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/modernize/ModernizeTidyModule.cpp
===================================================================
--- clang-tidy/modernize/ModernizeTidyModule.cpp
+++ clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -32,6 +32,7 @@
#include "UseNoexceptCheck.h"
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
+#include "UseTrailingReturnCheck.h"
#include "UseTransparentFunctorsCheck.h"
#include "UseUncaughtExceptionsCheck.h"
#include "UseUsingCheck.h"
@@ -77,6 +78,8 @@
CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
+ CheckFactories.registerCheck<UseTrailingReturnCheck>(
+ "modernize-use-trailing-return");
CheckFactories.registerCheck<UseTransparentFunctorsCheck>(
"modernize-use-transparent-functors");
CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
Index: clang-tidy/modernize/CMakeLists.txt
===================================================================
--- clang-tidy/modernize/CMakeLists.txt
+++ clang-tidy/modernize/CMakeLists.txt
@@ -26,6 +26,7 @@
UseNoexceptCheck.cpp
UseNullptrCheck.cpp
UseOverrideCheck.cpp
+ UseTrailingReturnCheck.cpp
UseTransparentFunctorsCheck.cpp
UseUncaughtExceptionsCheck.cpp
UseUsingCheck.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits