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 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("modernize-use-noexcept"); CheckFactories.registerCheck("modernize-use-nullptr"); CheckFactories.registerCheck("modernize-use-override"); + CheckFactories.registerCheck( + "modernize-use-trailing-return"); CheckFactories.registerCheck( "modernize-use-transparent-functors"); CheckFactories.registerCheck( Index: clang-tidy/modernize/UseTrailingReturnCheck.h =================================================================== --- /dev/null +++ clang-tidy/modernize/UseTrailingReturnCheck.h @@ -0,0 +1,44 @@ +//===--- 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); + 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,205 @@ +//===--- 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 {}; + } + const FunctionTypeLoc FTL = + TSI->getTypeLoc().IgnoreParens().getAs(); + 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. + const 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 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; +} + +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()) { + diag(F.getLocation(), Message); // happens if e.g. clang cannot resolve all + // includes and the return type is unknow. + return {}; + } + + // if the return type has no local qualifiers, it's source range is accurate. + if (!F.getReturnType().hasLocalQualifiers()) + return ReturnTypeRange; + + const SourceLocation BeginF = expandIfMacroId(F.getBeginLoc(), SM); + const SourceLocation BeginNameF = expandIfMacroId(F.getLocation(), SM); + + // create tokens for everything before the name of the function. + std::pair 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 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()) { + diag(F.getLocation(), Message); // CV qualifiers in macros + return {}; + } + 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.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(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("f"); + assert(F && "Matcher is expected to find only FunctionDecls"); + + // 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(); + + const 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: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -226,6 +226,11 @@ Adds ``[[nodiscard]]`` attributes (introduced in C++17) to member functions to highlight at compile time which return values should not be ignored. +- New :doc:`modernize-use-trailing-return + ` check. + + Rewrites function signatures to use a trailing return type. + - New :doc:`readability-isolate-decl ` check. 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/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: test/clang-tidy/modernize-use-trailing-return.cpp =================================================================== --- /dev/null +++ test/clang-tidy/modernize-use-trailing-return.cpp @@ -0,0 +1,269 @@ +// RUN: %check_clang_tidy %s modernize-use-trailing-return %t -- -- --std=c++14 -fdeclspec + +namespace std { + template + 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 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 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 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;{{$}} +inline const std::vector 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 volatile;{{$}} +inline std::vector 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 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::* e6(); +// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use a trailing return type for this function [modernize-use-trailing-return] +int (std::vector::*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;{{$}} + +// +// 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 +using Real = T; +#define PRECISION float +Real 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 { return 0.; }{{$}} + +// +// 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 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 {};