[clang-tidy] Add support for lambda-expression in use-trailing-return-type check (#135383)
Add support for lambda-expression in `use-trailing-return-type` check. Added two new options: 1. `TransformFunctions` will trigger function declarations to use trailing return type. 2. `TransformLambdas` will trigger lambda expression to use trailing return type if it was not stated explicitly. Fixed false positives when lambda was matched as a function in C++11 mode. Closes https://github.com/llvm/llvm-project/issues/95711
This commit is contained in:
@@ -17,6 +17,30 @@
|
||||
#include <cctype>
|
||||
#include <optional>
|
||||
|
||||
namespace clang::tidy {
|
||||
|
||||
template <>
|
||||
struct OptionEnumMapping<
|
||||
modernize::UseTrailingReturnTypeCheck::TransformLambda> {
|
||||
static llvm::ArrayRef<std::pair<
|
||||
modernize::UseTrailingReturnTypeCheck::TransformLambda, StringRef>>
|
||||
getEnumMapping() {
|
||||
static constexpr std::pair<
|
||||
modernize::UseTrailingReturnTypeCheck::TransformLambda, StringRef>
|
||||
Mapping[] = {
|
||||
{modernize::UseTrailingReturnTypeCheck::TransformLambda::All,
|
||||
"all"},
|
||||
{modernize::UseTrailingReturnTypeCheck::TransformLambda::
|
||||
AllExceptAuto,
|
||||
"all_except_auto"},
|
||||
{modernize::UseTrailingReturnTypeCheck::TransformLambda::None,
|
||||
"none"}};
|
||||
return Mapping;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang::tidy
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::modernize {
|
||||
@@ -111,10 +135,17 @@ public:
|
||||
private:
|
||||
const FunctionDecl &F;
|
||||
};
|
||||
|
||||
AST_MATCHER(LambdaExpr, hasExplicitResultType) {
|
||||
return Node.hasExplicitResultType();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr llvm::StringLiteral ErrorMessageOnFunction =
|
||||
"use a trailing return type for this function";
|
||||
constexpr llvm::StringLiteral ErrorMessageOnLambda =
|
||||
"use a trailing return type for this lambda";
|
||||
|
||||
static SourceLocation expandIfMacroId(SourceLocation Loc,
|
||||
const SourceManager &SM) {
|
||||
@@ -329,6 +360,48 @@ findReturnTypeAndCVSourceRange(const FunctionDecl &F, const TypeLoc &ReturnLoc,
|
||||
return ReturnTypeRange;
|
||||
}
|
||||
|
||||
static SourceLocation findLambdaTrailingReturnInsertLoc(
|
||||
const CXXMethodDecl *Method, const SourceManager &SM,
|
||||
const LangOptions &LangOpts, const ASTContext &Ctx) {
|
||||
// 'requires' keyword is present in lambda declaration
|
||||
if (Method->getTrailingRequiresClause()) {
|
||||
SourceLocation ParamEndLoc;
|
||||
if (Method->param_empty())
|
||||
ParamEndLoc = Method->getBeginLoc();
|
||||
else
|
||||
ParamEndLoc = Method->getParametersSourceRange().getEnd();
|
||||
|
||||
std::pair<FileID, unsigned> ParamEndLocInfo =
|
||||
SM.getDecomposedLoc(ParamEndLoc);
|
||||
StringRef Buffer = SM.getBufferData(ParamEndLocInfo.first);
|
||||
|
||||
Lexer Lexer(SM.getLocForStartOfFile(ParamEndLocInfo.first), LangOpts,
|
||||
Buffer.begin(), Buffer.data() + ParamEndLocInfo.second,
|
||||
Buffer.end());
|
||||
|
||||
Token Token;
|
||||
while (!Lexer.LexFromRawLexer(Token)) {
|
||||
if (Token.is(tok::raw_identifier)) {
|
||||
IdentifierInfo &Info = Ctx.Idents.get(StringRef(
|
||||
SM.getCharacterData(Token.getLocation()), Token.getLength()));
|
||||
Token.setIdentifierInfo(&Info);
|
||||
Token.setKind(Info.getTokenID());
|
||||
}
|
||||
|
||||
if (Token.is(tok::kw_requires))
|
||||
return Token.getLocation().getLocWithOffset(-1);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// If no requires clause, insert before the body
|
||||
if (const Stmt *Body = Method->getBody())
|
||||
return Body->getBeginLoc().getLocWithOffset(-1);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static void keepSpecifiers(std::string &ReturnType, std::string &Auto,
|
||||
SourceRange ReturnTypeCVRange, const FunctionDecl &F,
|
||||
const FriendDecl *Fr, const ASTContext &Ctx,
|
||||
@@ -382,14 +455,43 @@ static void keepSpecifiers(std::string &ReturnType, std::string &Auto,
|
||||
}
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto F = functionDecl(
|
||||
unless(anyOf(hasTrailingReturn(), returns(voidType()),
|
||||
cxxConversionDecl(), cxxMethodDecl(isImplicit()))))
|
||||
.bind("Func");
|
||||
UseTrailingReturnTypeCheck::UseTrailingReturnTypeCheck(
|
||||
StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
TransformFunctions(Options.get("TransformFunctions", true)),
|
||||
TransformLambdas(Options.get("TransformLambdas", TransformLambda::All)) {
|
||||
|
||||
Finder->addMatcher(F, this);
|
||||
Finder->addMatcher(friendDecl(hasDescendant(F)).bind("Friend"), this);
|
||||
if (TransformFunctions == false && TransformLambdas == TransformLambda::None)
|
||||
this->configurationDiag(
|
||||
"The check 'modernize-use-trailing-return-type' will not perform any "
|
||||
"analysis because 'TransformFunctions' and 'TransformLambdas' are "
|
||||
"disabled.");
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::storeOptions(
|
||||
ClangTidyOptions::OptionMap &Opts) {
|
||||
Options.store(Opts, "TransformFunctions", TransformFunctions);
|
||||
Options.store(Opts, "TransformLambdas", TransformLambdas);
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto F =
|
||||
functionDecl(
|
||||
unless(anyOf(
|
||||
hasTrailingReturn(), returns(voidType()), cxxConversionDecl(),
|
||||
cxxMethodDecl(
|
||||
anyOf(isImplicit(),
|
||||
hasParent(cxxRecordDecl(hasParent(lambdaExpr()))))))))
|
||||
.bind("Func");
|
||||
|
||||
if (TransformFunctions) {
|
||||
Finder->addMatcher(F, this);
|
||||
Finder->addMatcher(friendDecl(hasDescendant(F)).bind("Friend"), this);
|
||||
}
|
||||
|
||||
if (TransformLambdas != TransformLambda::None)
|
||||
Finder->addMatcher(
|
||||
lambdaExpr(unless(hasExplicitResultType())).bind("Lambda"), this);
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::registerPPCallbacks(
|
||||
@@ -401,8 +503,13 @@ void UseTrailingReturnTypeCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
assert(PP && "Expected registerPPCallbacks() to have been called before so "
|
||||
"preprocessor is available");
|
||||
|
||||
const auto *F = Result.Nodes.getNodeAs<FunctionDecl>("Func");
|
||||
if (const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("Lambda")) {
|
||||
diagOnLambda(Lambda, Result);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *Fr = Result.Nodes.getNodeAs<FriendDecl>("Friend");
|
||||
const auto *F = Result.Nodes.getNodeAs<FunctionDecl>("Func");
|
||||
assert(F && "Matcher is expected to find only FunctionDecls");
|
||||
|
||||
// Three-way comparison operator<=> is syntactic sugar and generates implicit
|
||||
@@ -495,4 +602,41 @@ void UseTrailingReturnTypeCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
<< FixItHint::CreateInsertion(InsertionLoc, " -> " + ReturnType);
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::diagOnLambda(
|
||||
const LambdaExpr *Lambda,
|
||||
const ast_matchers::MatchFinder::MatchResult &Result) {
|
||||
|
||||
const CXXMethodDecl *Method = Lambda->getCallOperator();
|
||||
if (!Method || Lambda->hasExplicitResultType())
|
||||
return;
|
||||
|
||||
const ASTContext *Ctx = Result.Context;
|
||||
const QualType ReturnType = Method->getReturnType();
|
||||
|
||||
// We can't write 'auto' in C++11 mode, try to write generic msg and bail out.
|
||||
if (ReturnType->isDependentType() &&
|
||||
Ctx->getLangOpts().LangStd == LangStandard::lang_cxx11) {
|
||||
if (TransformLambdas == TransformLambda::All)
|
||||
diag(Lambda->getBeginLoc(), ErrorMessageOnLambda);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReturnType->isUndeducedAutoType() &&
|
||||
TransformLambdas == TransformLambda::AllExceptAuto)
|
||||
return;
|
||||
|
||||
const SourceLocation TrailingReturnInsertLoc =
|
||||
findLambdaTrailingReturnInsertLoc(Method, *Result.SourceManager,
|
||||
getLangOpts(), *Result.Context);
|
||||
|
||||
if (TrailingReturnInsertLoc.isValid())
|
||||
diag(Lambda->getBeginLoc(), "use a trailing return type for this lambda")
|
||||
<< FixItHint::CreateInsertion(
|
||||
TrailingReturnInsertLoc,
|
||||
" -> " +
|
||||
ReturnType.getAsString(Result.Context->getPrintingPolicy()));
|
||||
else
|
||||
diag(Lambda->getBeginLoc(), ErrorMessageOnLambda);
|
||||
}
|
||||
|
||||
} // namespace clang::tidy::modernize
|
||||
|
||||
@@ -26,18 +26,25 @@ struct ClassifiedToken {
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-trailing-return-type.html
|
||||
class UseTrailingReturnTypeCheck : public ClangTidyCheck {
|
||||
public:
|
||||
UseTrailingReturnTypeCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
UseTrailingReturnTypeCheck(StringRef Name, ClangTidyContext *Context);
|
||||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
|
||||
return LangOpts.CPlusPlus11;
|
||||
}
|
||||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
|
||||
Preprocessor *ModuleExpanderPP) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
|
||||
enum TransformLambda { All, AllExceptAuto, None };
|
||||
|
||||
private:
|
||||
Preprocessor *PP = nullptr;
|
||||
const bool TransformFunctions;
|
||||
const TransformLambda TransformLambdas;
|
||||
|
||||
void diagOnLambda(const LambdaExpr *Lambda,
|
||||
const ast_matchers::MatchFinder::MatchResult &Result);
|
||||
};
|
||||
|
||||
} // namespace clang::tidy::modernize
|
||||
|
||||
@@ -236,6 +236,13 @@ Changes in existing checks
|
||||
<clang-tidy/checks/modernize/use-std-numbers>` check to support math
|
||||
functions of different precisions.
|
||||
|
||||
- Improved :doc:`modernize-use-trailing-return-type
|
||||
<clang-tidy/checks/modernize/use-trailing-return-type>` check by adding
|
||||
support to modernize lambda signatures to use trailing return type and adding
|
||||
two new options: `TransformFunctions` and `TransformLambdas` to control
|
||||
whether function declarations and lambdas should be transformed by the check.
|
||||
Fixed false positives when lambda was matched as a function in C++11 mode.
|
||||
|
||||
- Improved :doc:`performance-move-const-arg
|
||||
<clang-tidy/checks/performance/move-const-arg>` check by fixing false
|
||||
negatives on ternary operators calling ``std::move``.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
modernize-use-trailing-return-type
|
||||
==================================
|
||||
|
||||
Rewrites function signatures to use a trailing return type
|
||||
Rewrites function and lambda 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).
|
||||
@@ -16,6 +16,7 @@ Example
|
||||
int f1();
|
||||
inline int f2(int arg) noexcept;
|
||||
virtual float f3() const && = delete;
|
||||
auto lambda = []() {};
|
||||
|
||||
transforms to:
|
||||
|
||||
@@ -24,6 +25,7 @@ transforms to:
|
||||
auto f1() -> int;
|
||||
inline auto f2(int arg) -> int noexcept;
|
||||
virtual auto f3() const && -> float = delete;
|
||||
auto lambda = []() -> void {};
|
||||
|
||||
Known Limitations
|
||||
-----------------
|
||||
@@ -66,3 +68,25 @@ a careless rewrite would produce the following output:
|
||||
This code fails to compile because the S in the context of f refers to the equally named function parameter.
|
||||
Similarly, the S in the context of m refers to the equally named class member.
|
||||
The check can currently only detect and avoid a clash with a function parameter name.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. option:: TransformFunctions
|
||||
|
||||
When set to `true`, function declarations will be transformed to use trailing
|
||||
return. Default is `true`.
|
||||
|
||||
.. option:: TransformLambdas
|
||||
|
||||
Controls how lambda expressions are transformed to use trailing
|
||||
return type. Possible values are:
|
||||
|
||||
* `all` - Transform all lambda expressions without an explicit return type
|
||||
to use trailing return type. If type can not be deduced, ``auto`` will be
|
||||
used since C++14 and generic message will be emitted otherwise.
|
||||
* `all_except_auto` - Transform all lambda expressions except those whose return
|
||||
type can not be deduced.
|
||||
* `none` - Do not transform any lambda expressions.
|
||||
|
||||
Default is `all`.
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// RUN: %check_clang_tidy -std=c++14-or-later %s modernize-use-trailing-return-type %t -- -- -fno-delayed-template-parsing
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
class vector {};
|
||||
|
||||
class string {};
|
||||
} // namespace std
|
||||
|
||||
void test_lambda_positive() {
|
||||
auto l1 = [](auto x) { return x; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l1 = [](auto x) -> auto { return x; };{{$}}
|
||||
}
|
||||
|
||||
template <template <typename> class C>
|
||||
void test_lambda_positive_template() {
|
||||
auto l1 = []() { return C<int>{}; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l1 = []() -> auto { return C<int>{}; };{{$}}
|
||||
auto l2 = []() { return 0; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l2 = []() -> auto { return 0; };{{$}}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-trailing-return-type %t -- -- -fno-delayed-template-parsing
|
||||
|
||||
namespace std {
|
||||
template <typename T, typename U>
|
||||
struct is_same { static constexpr auto value = false; };
|
||||
|
||||
template <typename T>
|
||||
struct is_same<T, T> { static constexpr auto value = true; };
|
||||
|
||||
template <typename T>
|
||||
concept floating_point = std::is_same<T, float>::value || std::is_same<T, double>::value || std::is_same<T, long double>::value;
|
||||
}
|
||||
|
||||
void test_lambda_positive() {
|
||||
auto l1 = []<typename T, typename U>(T x, U y) { return x + y; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l1 = []<typename T, typename U>(T x, U y) -> auto { return x + y; };{{$}}
|
||||
auto l2 = [](auto x) requires requires { x + x; } { return x; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l2 = [](auto x) -> auto requires requires { x + x; } { return x; };{{$}}
|
||||
auto l3 = [](auto x) requires std::floating_point<decltype(x)> { return x; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l3 = [](auto x) -> auto requires std::floating_point<decltype(x)> { return x; };{{$}}
|
||||
auto l4 = [](int x) consteval { return x; };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l4 = [](int x) consteval -> int { return x; };{{$}}
|
||||
// Complete complex example
|
||||
auto l5 = []<typename T, typename U>(T x, U y) constexpr noexcept
|
||||
requires std::floating_point<T> && std::floating_point<U>
|
||||
{ return x * y; };
|
||||
// CHECK-MESSAGES: :[[@LINE-3]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto l5 = []<typename T, typename U>(T x, U y) constexpr noexcept{{$}}
|
||||
// CHECK-FIXES: {{^}} -> auto requires std::floating_point<T> && std::floating_point<U>{{$}}
|
||||
// CHECK-FIXES: {{^}} { return x * y; };{{$}}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// RUN: %check_clang_tidy -check-suffix=ALL -std=c++11-or-later %s modernize-use-trailing-return-type %t --\
|
||||
// RUN: -config="{CheckOptions: {modernize-use-trailing-return-type.TransformLambdas: all, \
|
||||
// RUN: modernize-use-trailing-return-type.TransformFunctions: false}}" \
|
||||
// RUN: -- -fno-delayed-template-parsing
|
||||
// RUN: %check_clang_tidy -check-suffix=NOAUTO -std=c++11-or-later %s modernize-use-trailing-return-type %t --\
|
||||
// RUN: -config="{CheckOptions: {modernize-use-trailing-return-type.TransformLambdas: all_except_auto, \
|
||||
// RUN: modernize-use-trailing-return-type.TransformFunctions: false}}" \
|
||||
// RUN: -- -fno-delayed-template-parsing
|
||||
// RUN: %check_clang_tidy -check-suffix=NONE -std=c++11-or-later %s modernize-use-trailing-return-type %t --\
|
||||
// RUN: -config="{CheckOptions: {modernize-use-trailing-return-type.TransformLambdas: none, \
|
||||
// RUN: modernize-use-trailing-return-type.TransformFunctions: true}}" \
|
||||
// RUN: -- -fno-delayed-template-parsing
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
class vector {};
|
||||
|
||||
class string {};
|
||||
} // namespace std
|
||||
|
||||
void test_lambda_positive() {
|
||||
auto l01 = [] {};
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:14: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l01 = [] -> void {};{{$}}
|
||||
auto l1 = []() {};
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l1 = []() -> void {};{{$}}
|
||||
auto l2 = []() { return 42; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l2 = []() -> int { return 42; };{{$}}
|
||||
auto l3 = [](int x, double y) { return x * y; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l3 = [](int x, double y) -> double { return x * y; };{{$}}
|
||||
|
||||
int capture_int = 10;
|
||||
double capture_double = 3.14;
|
||||
int* capture_ptr = nullptr;
|
||||
|
||||
auto l4 = [capture_int]() { return capture_int; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l4 = [capture_int]() -> int { return capture_int; };{{$}}
|
||||
auto l5 = [capture_int, &capture_double](char c) { return capture_int + capture_double + c; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l5 = [capture_int, &capture_double](char c) -> double { return capture_int + capture_double + c; };{{$}}
|
||||
auto l6 = [capture_int]() constexpr mutable noexcept { return ++capture_int; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l6 = [capture_int]() constexpr mutable noexcept -> int { return ++capture_int; };{{$}}
|
||||
auto l7 = [&capture_ptr]() { return capture_ptr; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l7 = [&capture_ptr]() -> int * { return capture_ptr; };{{$}}
|
||||
auto l8 = [&capture_int]() { return capture_int; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l8 = [&capture_int]() -> int { return capture_int; };{{$}}
|
||||
auto l9 = [] { return std::vector<std::vector<int>>{}; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l9 = [] -> std::vector<std::vector<int>> { return std::vector<std::vector<int>>{}; };{{$}}
|
||||
auto l10 = [] { const char* const * const * const ptr = nullptr; return ptr; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:14: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-MESSAGES-NOAUTO: :[[@LINE-2]]:14: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-ALL: {{^}} auto l10 = [] -> const char *const *const * { const char* const * const * const ptr = nullptr; return ptr; };{{$}}
|
||||
}
|
||||
|
||||
// In c++11 mode we can not write 'auto' type, see *-cxx14.cpp for fixes.
|
||||
template <template <typename> class C>
|
||||
void test_lambda_positive_template() {
|
||||
auto l1 = []() { return C<int>{}; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
auto l2 = []() { return 0; };
|
||||
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:13: warning: use a trailing return type for this lambda [modernize-use-trailing-return-type]
|
||||
}
|
||||
|
||||
void test_lambda_negative() {
|
||||
auto l1_good = [](int arg) -> int { return 0; };
|
||||
}
|
||||
|
||||
// this function is solely used to not to get "wrong config error" from the check.
|
||||
int f();
|
||||
// CHECK-MESSAGES-NONE: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES-NONE: {{^}}auto f() -> int;{{$}}
|
||||
@@ -0,0 +1,5 @@
|
||||
// RUN: %check_clang_tidy -std=c++11-or-later %s modernize-use-trailing-return-type %t \
|
||||
// RUN: -config="{CheckOptions: {modernize-use-trailing-return-type.TransformLambdas: none, \
|
||||
// RUN: modernize-use-trailing-return-type.TransformFunctions: false}}"
|
||||
|
||||
// CHECK-MESSAGES: warning: The check 'modernize-use-trailing-return-type' will not perform any analysis because 'TransformFunctions' and 'TransformLambdas' are disabled. [clang-tidy-config]
|
||||
@@ -594,5 +594,3 @@ struct D2 : B {
|
||||
operator double();
|
||||
};
|
||||
|
||||
auto l1 = [](int arg) {};
|
||||
auto l2 = [](int arg) -> double { return 0; };
|
||||
|
||||
Reference in New Issue
Block a user