bernhardmgruber updated this revision to Diff 182385.
bernhardmgruber marked 19 inline comments as done.
bernhardmgruber added a comment.

Addressed most of the new review comments (mainly uppercasing start of 
comments).


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/ReleaseNotes.rst
  docs/clang-tidy/checks/list.rst
  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,283 @@
+// RUN: %check_clang_tidy %s modernize-use-trailing-return %t -- -- --std=c++14 -fdeclspec
+
+namespace std {
+    template <typename T>
+    class vector;
+
+    class string;
+}
+
+//
+// Functions
+//
+
+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;{{$}}
+
+//
+// Functions with formatting
+//
+
+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 a4(int   arg   )   ;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto a4(int   arg   ) -> int   ;{{$}}
+int a5
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto a5{{$}}
+(int arg);
+// CHECK-FIXES: {{^}}(int arg) -> int;{{$}}
+
+//
+// Functions with qualifiers and specifiers
+//
+
+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;{{$}}
+extern "C" int d2(int arg);
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}extern "C" auto d2(int arg) -> int;{{$}}
+inline int d3(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 d3(int arg) -> int noexcept(true);{{$}}
+inline int d4(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 d4(int arg) -> int try { } catch(...) { }{{$}}
+
+//
+// Functions in namespaces
+//
+
+namespace N {
+    int e1();
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}    auto e1() -> int;{{$}}
+int N::e1() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto N::e1() -> int {}{{$}}
+
+//
+// Functions with complex return types
+//
+
+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;{{$}}
+int (*e3())(double);
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use a trailing return type for this function [modernize-use-trailing-return]
+struct A;
+int A::* e5();
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use a trailing return type for this function [modernize-use-trailing-return]
+int std::vector<std::string>::* e6();
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use a trailing return type for this function [modernize-use-trailing-return]
+int (std::vector<std::string>::*e7())(double);
+// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use a trailing return type for this function [modernize-use-trailing-return]
+int* e8();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto e8() -> int*;{{$}}
+
+// TODO: not matched by the AST matcher
+//decltype(auto) e6();
+// _HECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// _HECK-FIXES: {{^}}auto e6() -> decltype(auto);{{$}}
+
+//
+// Methods
+//
+
+struct B {
+    B& operator=(const B&);
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}    auto operator=(const B&) -> 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;{{$}}
+
+    virtual float base4() volatile = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}    virtual auto base4() volatile -> float = 0;{{$}}
+
+    double base5(int, bool b) &&;
+// 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) && -> double;{{$}}
+
+    double base6(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 base6(int, bool b) const && -> double;{{$}}
+
+    double base7(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 base7(int, bool b) const & -> double = delete;{{$}}
+
+    double base8(int, bool b) const volatile & = delete;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}    auto base8(int, bool b) const volatile & -> double = delete;{{$}}
+};
+
+double B::base1(int, bool b) {}
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto B::base1(int, bool b) -> double {}{{$}}
+
+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 { }{{$}}
+};
+
+//
+// Functions with attributes
+//
+
+int g1() [[asdf]];
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto g1() -> int {{[[][[]}}asdf{{[]][]]}};{{$}}
+[[noreturn]] int g2();
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}{{[[][[]}}noreturn{{[]][]]}} auto g2() -> int;{{$}}
+int g2 [[noreturn]] ();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto g2 {{[[][[]}}noreturn{{[]][]]}} () -> int;{{$}}
+
+//
+// Templates
+//
+template <typename Container>
+[[maybe_unused]] typename Container::value_type const volatile&& t1(Container& C) noexcept;
+// CHECK-MESSAGES: :[[@LINE-1]]:66: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}{{[[][[]}}maybe_unused{{[]][]]}} auto t1(Container& C) -> typename Container::value_type const volatile&& noexcept;{{$}}
+
+//
+// Macros
+//
+
+#define DWORD unsigned int
+DWORD h1();
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto h1() -> DWORD;{{$}}
+#define INT int
+#define UNSIGNED unsigned
+UNSIGNED INT h2();
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto h2() -> UNSIGNED INT;{{$}}
+#define CONST const
+CONST int h3();
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use a trailing return type for this function [modernize-use-trailing-return]
+#define ALWAYS_INLINE inline
+#define DLL_EXPORT __declspec(dllexport)
+ALWAYS_INLINE DLL_EXPORT int h4();
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}ALWAYS_INLINE DLL_EXPORT auto h4() -> int;{{$}}
+#define ANOTHER_ATTRIBUTE __attribute__((deprecated))
+int h5() ANOTHER_ATTRIBUTE;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto h5() -> int ANOTHER_ATTRIBUTE;{{$}}
+#define FUNCTION_NAME(a, b) a##b
+int FUNCTION_NAME(foo, bar)();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto FUNCTION_NAME(foo, bar)() -> int;{{$}}
+#define DEFINE_FUNCTION_1(a, b) int a##b()
+DEFINE_FUNCTION_1(foo, bar);
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use a trailing return type for this function [modernize-use-trailing-return]
+#define DEFINE_FUNCTION_2 int foo(int arg);
+DEFINE_FUNCTION_2
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use a trailing return type for this function [modernize-use-trailing-return]
+#define DLL_EXPORT_CONST __declspec(dllexport) const
+DLL_EXPORT_CONST int h6();
+// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use a trailing return type for this function [modernize-use-trailing-return]
+
+template <typename T>
+using Real = T;
+#define PRECISION float
+Real<PRECISION> h7() { return 0.; }
+// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}auto h7() -> Real<PRECISION> { return 0.; }{{$}}
+
+#define MAYBE_UNUSED_MACRO [[maybe_unused]]
+template <typename Container>
+MAYBE_UNUSED_MACRO typename Container::value_type const volatile** const myFunnyFunction(Container& C) noexcept;
+// CHECK-MESSAGES: :[[@LINE-1]]:74: warning: use a trailing return type for this function [modernize-use-trailing-return]
+// CHECK-FIXES: {{^}}MAYBE_UNUSED_MACRO auto myFunnyFunction(Container& C) -> typename Container::value_type const volatile** const noexcept;{{$}}
+
+//
+// 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 {
+    D2();
+    virtual ~D2();
+    
+    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();
+};
+
+auto l1 = [](int arg) {};
+auto l2 = [](int arg) -> 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,34 @@
+.. 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;
+
+Known Limitations
+-----------------
+
+The following categories of return types cannot be rewritten currently:
+* function pointers
+* member function pointers
+* member pointers
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -211,6 +211,7 @@
    modernize-use-noexcept
    modernize-use-nullptr
    modernize-use-override
+   modernize-use-trailing-return
    modernize-use-transparent-functors
    modernize-use-uncaught-exceptions
    modernize-use-using
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -67,7 +67,10 @@
 Improvements to clang-tidy
 --------------------------
 
-- ...
+- New :doc:`modernize-use-trailing-return
+  <clang-tidy/checks/modernize-use-trailing-return>` check.
+
+  Rewrites function signatures to use a trailing return type.
 
 Improvements to include-fixer
 -----------------------------
Index: clang-tidy/modernize/UseTrailingReturnCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/modernize/UseTrailingReturnCheck.h
@@ -0,0 +1,48 @@
+//===--- 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;
+
+private:
+  SourceLocation findTrailingReturnTypeSourceLocation(
+      const FunctionDecl &F, const ASTContext &Ctx, const SourceManager &SM,
+      const LangOptions &LangOpts);
+  llvm::Optional<SmallVector<Token, 8>>
+  nonMacroTokensBeforeFunctionName(const FunctionDecl &F, const ASTContext &Ctx,
+                                   const SourceManager &SM,
+                                   const LangOptions &LangOpts);
+  SourceRange findReturnTypeAndCVSourceRange(const FunctionDecl &F,
+                                             const ASTContext &Ctx,
+                                             const SourceManager &SM,
+                                             const LangOptions &LangOpts);
+};
+
+} // 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,222 @@
+//===--- 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"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+constexpr llvm::StringLiteral Message =
+    "use a trailing return type for this function";
+
+static SourceLocation expandIfMacroId(SourceLocation Loc,
+                                      const SourceManager &SM) {
+  if (Loc.isMacroID())
+    Loc = SM.getImmediateExpansionRange(Loc).getBegin();
+  return Loc;
+}
+
+SourceLocation UseTrailingReturnCheck::findTrailingReturnTypeSourceLocation(
+    const FunctionDecl &F, const ASTContext &Ctx, const SourceManager &SM,
+    const LangOptions &LangOpts) {
+  // We start with the location of the closing parenthesis.
+  const TypeSourceInfo *TSI = F.getTypeSourceInfo();
+  if (!TSI) {
+    diag(F.getLocation(), Message);
+    return {};
+  }
+  FunctionTypeLoc FTL =
+      TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
+  if (!FTL) {
+    diag(F.getLocation(), Message);
+    return {};
+  }
+
+  // If the function argument list ends inside of a macro, it is dangerous to
+  // start lexing from here - bail out.
+  SourceLocation ClosingParen = FTL.getRParenLoc();
+  if (ClosingParen.isMacroID()) {
+    diag(F.getLocation(), Message);
+    return {};
+  }
+
+  SourceLocation Result =
+      Lexer::getLocForEndOfToken(ClosingParen, 0, SM, LangOpts);
+
+  // Skip subsequent CV and ref qualifiers.
+  std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(Result);
+  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;
+  while (!Lexer.LexFromRawLexer(T)) {
+    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.isOneOf(tok::amp, tok::ampamp, tok::kw_const, tok::kw_volatile)) {
+      Result = T.getEndLoc();
+      continue;
+    }
+
+    break;
+  }
+
+  return Result;
+}
+
+llvm::Optional<SmallVector<Token, 8>>
+UseTrailingReturnCheck::nonMacroTokensBeforeFunctionName(
+    const FunctionDecl &F, const ASTContext &Ctx, const SourceManager &SM,
+    const LangOptions &LangOpts) {
+  SourceLocation BeginF = expandIfMacroId(F.getBeginLoc(), SM);
+  SourceLocation BeginNameF = expandIfMacroId(F.getLocation(), SM);
+
+  // Create tokens for everything before the name of the function.
+  std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(BeginF);
+  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(BeginNameF, T.getLocation()))
+      break;
+    if (T.is(tok::raw_identifier)) {
+      IdentifierInfo &Info = Ctx.Idents.get(
+          StringRef(SM.getCharacterData(T.getLocation()), T.getLength()));
+      if (Info.hasMacroDefinition()) {
+        // The CV qualifiers of the return type are inside macros
+        diag(F.getLocation(), Message);
+        return {};
+      }
+      T.setIdentifierInfo(&Info);
+      T.setKind(Info.getTokenID());
+    }
+    Tokens.push_back(T);
+  }
+  return Tokens;
+}
+
+SourceRange UseTrailingReturnCheck::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();
+  if (ReturnTypeRange.isInvalid()) {
+    // Happens if e.g. clang cannot resolve all includes and the return type is
+    // unknown.
+    diag(F.getLocation(), Message);
+    return {};
+  }
+
+  // If the return type has no local qualifiers, it's source range is accurate.
+  if (!F.getReturnType().hasLocalQualifiers())
+    return ReturnTypeRange;
+
+  // Include const and volatile to the left and right of the return type.
+  llvm::Optional<SmallVector<Token, 8>> MaybeTokens =
+      nonMacroTokensBeforeFunctionName(F, Ctx, SM, LangOpts);
+  if (!MaybeTokens)
+    return {};
+  const SmallVector<Token, 8> &Tokens = *MaybeTokens;
+
+  auto IsCV = [](Token T) {
+    return T.isOneOf(tok::kw_const, tok::kw_volatile);
+  };
+
+  bool ExtendedLeft = false;
+  for (size_t 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 = static_cast<int>(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 (size_t 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(),
+                                cxxMethodDecl(isImplicit()))))
+          .bind("f"),
+      this);
+}
+
+void UseTrailingReturnCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *F = Result.Nodes.getNodeAs<FunctionDecl>("f");
+  assert(F && "Matcher is expected to find only FunctionDecls");
+
+  if (F->getLocation().isInvalid())
+    return;
+
+  // TODO: implement those
+  if (F->getDeclaredReturnType()->isFunctionPointerType() ||
+      F->getDeclaredReturnType()->isMemberFunctionPointerType() ||
+      F->getDeclaredReturnType()->isMemberPointerType()) {
+    diag(F->getLocation(), Message);
+    return;
+  }
+
+  const ASTContext &Ctx = *Result.Context;
+  const SourceManager &SM = *Result.SourceManager;
+  const LangOptions &LangOpts = getLangOpts();
+
+  SourceLocation InsertionLoc =
+      findTrailingReturnTypeSourceLocation(*F, Ctx, SM, LangOpts);
+  if (InsertionLoc.isInvalid())
+    return;
+
+  // Using the declared return type via F->getDeclaredReturnType().getAsString()
+  // discards user formatting and order of const, volatile, type, whitespace,
+  // space before & ... .
+  SourceRange ReturnTypeCVRange =
+      findReturnTypeAndCVSourceRange(*F, Ctx, SM, LangOpts);
+  if (ReturnTypeCVRange.isInvalid())
+    return;
+  StringRef ReturnType = tooling::fixit::getText(ReturnTypeCVRange, Ctx);
+
+  diag(F->getLocation(), Message)
+      << FixItHint::CreateReplacement(ReturnTypeCVRange, "auto")
+      << FixItHint::CreateInsertion(InsertionLoc, (" -> " + ReturnType).str());
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/modernize/ModernizeTidyModule.cpp
===================================================================
--- clang-tidy/modernize/ModernizeTidyModule.cpp
+++ clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -36,6 +36,7 @@
 #include "UseNoexceptCheck.h"
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
+#include "UseTrailingReturnCheck.h"
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
 #include "UseUsingCheck.h"
@@ -88,6 +89,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
@@ -30,6 +30,7 @@
   UseNoexceptCheck.cpp
   UseNullptrCheck.cpp
   UseOverrideCheck.cpp
+  UseTrailingReturnCheck.cpp
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
   UseUsingCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to