bernhardmgruber updated this revision to Diff 179734.
bernhardmgruber added a comment.

updated diff to one with full context


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,7 @@
+.. title:: clang-tidy - modernize-use-trailing-return
+
+modernize-use-trailing-return
+======================
+
+
+Rewrites function signatures to use a trailing return type.
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,209 @@
+//===--- 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 {
+namespace {
+
+// very similar to UseOverrideCheck
+SourceLocation findTrailingReturnTypeLocation(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 paranthesis");
+}
+
+SourceRange findReturnTypeAndCVRange(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
+  auto 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;
+  std::vector<Token> 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;
+}
+} // namespace
+
+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()) {
+    auto d = 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 &opts = getLangOpts();
+
+  auto returnTypeCVRange = findReturnTypeAndCVRange(*f, ctx, sm, opts);
+  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, opts);
+  if (!charRange.isValid())
+    return;
+  const auto insertionLoc =
+      findTrailingReturnTypeLocation(charRange, ctx, sm, opts);
+
+  // extract return type as string
+  const auto returnType = [&] {
+    // using the declared return type discards user formatting and order (order
+    // of const, volatile, type, whitespace, space before & ...) return
+    // f->getDeclaredReturnType().getAsString();
+
+    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, opts));
+    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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to