forked from OSchip/llvm-project
Add the modernize-use-trailing-return check to rewrite function signatures to use trailing return types.
Patch by Bernhard Manfred Gruber. llvm-svn: 360345
This commit is contained in:
parent
70674549f1
commit
8e015b2e94
|
@ -30,6 +30,7 @@ add_clang_library(clangTidyModernizeModule
|
|||
UseNoexceptCheck.cpp
|
||||
UseNullptrCheck.cpp
|
||||
UseOverrideCheck.cpp
|
||||
UseTrailingReturnTypeCheck.cpp
|
||||
UseTransparentFunctorsCheck.cpp
|
||||
UseUncaughtExceptionsCheck.cpp
|
||||
UseUsingCheck.cpp
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "UseNoexceptCheck.h"
|
||||
#include "UseNullptrCheck.h"
|
||||
#include "UseOverrideCheck.h"
|
||||
#include "UseTrailingReturnTypeCheck.h"
|
||||
#include "UseTransparentFunctorsCheck.h"
|
||||
#include "UseUncaughtExceptionsCheck.h"
|
||||
#include "UseUsingCheck.h"
|
||||
|
@ -87,6 +88,8 @@ public:
|
|||
CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
|
||||
CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
|
||||
CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
|
||||
CheckFactories.registerCheck<UseTrailingReturnTypeCheck>(
|
||||
"modernize-use-trailing-return-type");
|
||||
CheckFactories.registerCheck<UseTransparentFunctorsCheck>(
|
||||
"modernize-use-transparent-functors");
|
||||
CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
|
||||
|
|
|
@ -0,0 +1,477 @@
|
|||
//===--- UseTrailingReturnTypeCheck.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 "UseTrailingReturnTypeCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/RecursiveASTVisitor.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/Tooling/FixIt.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace modernize {
|
||||
namespace {
|
||||
struct UnqualNameVisitor : public RecursiveASTVisitor<UnqualNameVisitor> {
|
||||
public:
|
||||
UnqualNameVisitor(const FunctionDecl &F, const SourceManager &SM)
|
||||
: F(F), SM(SM) {}
|
||||
|
||||
bool Collision = false;
|
||||
|
||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||
|
||||
bool VisitUnqualName(StringRef UnqualName) {
|
||||
// Check for collisions with function arguments.
|
||||
for (ParmVarDecl *Param : F.parameters())
|
||||
if (const IdentifierInfo *Ident = Param->getIdentifier())
|
||||
if (Ident->getName() == UnqualName) {
|
||||
Collision = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TraverseTypeLoc(TypeLoc TL, bool Elaborated = false) {
|
||||
if (TL.isNull())
|
||||
return true;
|
||||
|
||||
if (!Elaborated) {
|
||||
switch (TL.getTypeLocClass()) {
|
||||
case TypeLoc::Record:
|
||||
if (VisitUnqualName(
|
||||
TL.getAs<RecordTypeLoc>().getTypePtr()->getDecl()->getName()))
|
||||
return false;
|
||||
break;
|
||||
case TypeLoc::Enum:
|
||||
if (VisitUnqualName(
|
||||
TL.getAs<EnumTypeLoc>().getTypePtr()->getDecl()->getName()))
|
||||
return false;
|
||||
break;
|
||||
case TypeLoc::TemplateSpecialization:
|
||||
if (VisitUnqualName(TL.getAs<TemplateSpecializationTypeLoc>()
|
||||
.getTypePtr()
|
||||
->getTemplateName()
|
||||
.getAsTemplateDecl()
|
||||
->getName()))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return RecursiveASTVisitor<UnqualNameVisitor>::TraverseTypeLoc(TL);
|
||||
}
|
||||
|
||||
// Replace the base method in order to call ower own
|
||||
// TraverseTypeLoc().
|
||||
bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) {
|
||||
return TraverseTypeLoc(TL.getUnqualifiedLoc());
|
||||
}
|
||||
|
||||
// Replace the base version to inform TraverseTypeLoc that the type is
|
||||
// elaborated.
|
||||
bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
||||
if (TL.getQualifierLoc() &&
|
||||
!TraverseNestedNameSpecifierLoc(TL.getQualifierLoc()))
|
||||
return false;
|
||||
return TraverseTypeLoc(TL.getNamedTypeLoc(), true);
|
||||
}
|
||||
|
||||
bool VisitDeclRefExpr(DeclRefExpr *S) {
|
||||
DeclarationName Name = S->getNameInfo().getName();
|
||||
return S->getQualifierLoc() || !Name.isIdentifier() || !VisitUnqualName(Name.getAsIdentifierInfo()->getName());
|
||||
}
|
||||
|
||||
private:
|
||||
const FunctionDecl &F;
|
||||
const SourceManager &SM;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
constexpr llvm::StringLiteral Message =
|
||||
"use a trailing return type for this function";
|
||||
|
||||
static SourceLocation expandIfMacroId(SourceLocation Loc,
|
||||
const SourceManager &SM) {
|
||||
if (Loc.isMacroID())
|
||||
Loc = expandIfMacroId(SM.getImmediateExpansionRange(Loc).getBegin(), SM);
|
||||
assert(!Loc.isMacroID() &&
|
||||
"SourceLocation must not be a macro ID after recursive expansion");
|
||||
return Loc;
|
||||
}
|
||||
|
||||
SourceLocation UseTrailingReturnTypeCheck::findTrailingReturnTypeSourceLocation(
|
||||
const FunctionDecl &F, const FunctionTypeLoc &FTL, const ASTContext &Ctx,
|
||||
const SourceManager &SM, const LangOptions &LangOpts) {
|
||||
// We start with the location of the closing parenthesis.
|
||||
SourceRange ExceptionSpecRange = F.getExceptionSpecSourceRange();
|
||||
if (ExceptionSpecRange.isValid())
|
||||
return Lexer::getLocForEndOfToken(ExceptionSpecRange.getEnd(), 0, SM,
|
||||
LangOpts);
|
||||
|
||||
// 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())
|
||||
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,
|
||||
tok::kw_restrict)) {
|
||||
Result = T.getEndLoc();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
static bool IsCVR(Token T) {
|
||||
return T.isOneOf(tok::kw_const, tok::kw_volatile, tok::kw_restrict);
|
||||
}
|
||||
|
||||
static bool IsSpecifier(Token T) {
|
||||
return T.isOneOf(tok::kw_constexpr, tok::kw_inline, tok::kw_extern,
|
||||
tok::kw_static, tok::kw_friend, tok::kw_virtual);
|
||||
}
|
||||
|
||||
static llvm::Optional<ClassifiedToken>
|
||||
classifyToken(const FunctionDecl &F, Preprocessor &PP, Token Tok) {
|
||||
ClassifiedToken CT;
|
||||
CT.T = Tok;
|
||||
CT.isQualifier = true;
|
||||
CT.isSpecifier = true;
|
||||
bool ContainsQualifiers = false;
|
||||
bool ContainsSpecifiers = false;
|
||||
bool ContainsSomethingElse = false;
|
||||
|
||||
Token End;
|
||||
End.setKind(tok::eof);
|
||||
SmallVector<Token, 2> Stream{Tok, End};
|
||||
PP.EnterTokenStream(Stream, false);
|
||||
while (true) {
|
||||
Token T;
|
||||
PP.Lex(T);
|
||||
if (T.is(tok::eof))
|
||||
break;
|
||||
|
||||
bool Qual = IsCVR(T);
|
||||
bool Spec = IsSpecifier(T);
|
||||
CT.isQualifier &= Qual;
|
||||
CT.isSpecifier &= Spec;
|
||||
ContainsQualifiers |= Qual;
|
||||
ContainsSpecifiers |= Spec;
|
||||
ContainsSomethingElse |= !Qual && !Spec;
|
||||
}
|
||||
|
||||
// If the Token/Macro contains more than one type of tokens, we would need
|
||||
// to split the macro in order to move parts to the trailing return type.
|
||||
if (ContainsQualifiers + ContainsSpecifiers + ContainsSomethingElse > 1)
|
||||
return llvm::None;
|
||||
|
||||
return CT;
|
||||
}
|
||||
|
||||
llvm::Optional<SmallVector<ClassifiedToken, 8>>
|
||||
UseTrailingReturnTypeCheck::classifyTokensBeforeFunctionName(
|
||||
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<ClassifiedToken, 8> ClassifiedTokens;
|
||||
while (!Lexer.LexFromRawLexer(T) &&
|
||||
SM.isBeforeInTranslationUnit(T.getLocation(), BeginNameF)) {
|
||||
if (T.is(tok::raw_identifier)) {
|
||||
IdentifierInfo &Info = Ctx.Idents.get(
|
||||
StringRef(SM.getCharacterData(T.getLocation()), T.getLength()));
|
||||
|
||||
if (Info.hasMacroDefinition()) {
|
||||
const MacroInfo *MI = PP->getMacroInfo(&Info);
|
||||
if (!MI || MI->isFunctionLike()) {
|
||||
// Cannot handle function style macros.
|
||||
diag(F.getLocation(), Message);
|
||||
return llvm::None;
|
||||
}
|
||||
}
|
||||
|
||||
T.setIdentifierInfo(&Info);
|
||||
T.setKind(Info.getTokenID());
|
||||
}
|
||||
|
||||
if (llvm::Optional<ClassifiedToken> CT = classifyToken(F, *PP, T))
|
||||
ClassifiedTokens.push_back(*CT);
|
||||
else {
|
||||
diag(F.getLocation(), Message);
|
||||
return llvm::None;
|
||||
}
|
||||
}
|
||||
|
||||
return ClassifiedTokens;
|
||||
}
|
||||
|
||||
static bool hasAnyNestedLocalQualifiers(QualType Type) {
|
||||
bool Result = Type.hasLocalQualifiers();
|
||||
if (Type->isPointerType())
|
||||
Result = Result || hasAnyNestedLocalQualifiers(
|
||||
Type->castAs<PointerType>()->getPointeeType());
|
||||
if (Type->isReferenceType())
|
||||
Result = Result || hasAnyNestedLocalQualifiers(
|
||||
Type->castAs<ReferenceType>()->getPointeeType());
|
||||
return Result;
|
||||
}
|
||||
|
||||
SourceRange UseTrailingReturnTypeCheck::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
|
||||
// qualifiers (const, volatile and restrict).
|
||||
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 (!hasAnyNestedLocalQualifiers(F.getReturnType()))
|
||||
return ReturnTypeRange;
|
||||
|
||||
// Include qualifiers to the left and right of the return type.
|
||||
llvm::Optional<SmallVector<ClassifiedToken, 8>> MaybeTokens =
|
||||
classifyTokensBeforeFunctionName(F, Ctx, SM, LangOpts);
|
||||
if (!MaybeTokens)
|
||||
return {};
|
||||
const SmallVector<ClassifiedToken, 8> &Tokens = *MaybeTokens;
|
||||
|
||||
ReturnTypeRange.setBegin(expandIfMacroId(ReturnTypeRange.getBegin(), SM));
|
||||
ReturnTypeRange.setEnd(expandIfMacroId(ReturnTypeRange.getEnd(), SM));
|
||||
|
||||
bool ExtendedLeft = false;
|
||||
for (size_t I = 0; I < Tokens.size(); I++) {
|
||||
// If we found the beginning of the return type, include left qualifiers.
|
||||
if (!SM.isBeforeInTranslationUnit(Tokens[I].T.getLocation(),
|
||||
ReturnTypeRange.getBegin()) &&
|
||||
!ExtendedLeft) {
|
||||
assert(I <= size_t(std::numeric_limits<int>::max()) &&
|
||||
"Integer overflow detected");
|
||||
for (int J = static_cast<int>(I) - 1; J >= 0 && Tokens[J].isQualifier;
|
||||
J--)
|
||||
ReturnTypeRange.setBegin(Tokens[J].T.getLocation());
|
||||
ExtendedLeft = true;
|
||||
}
|
||||
// If we found the end of the return type, include right qualifiers.
|
||||
if (SM.isBeforeInTranslationUnit(ReturnTypeRange.getEnd(),
|
||||
Tokens[I].T.getLocation())) {
|
||||
for (size_t J = I; J < Tokens.size() && Tokens[J].isQualifier; J++)
|
||||
ReturnTypeRange.setEnd(Tokens[J].T.getLocation());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!ReturnTypeRange.getBegin().isMacroID() &&
|
||||
"Return type source range begin must not be a macro");
|
||||
assert(!ReturnTypeRange.getEnd().isMacroID() &&
|
||||
"Return type source range end must not be a macro");
|
||||
return ReturnTypeRange;
|
||||
}
|
||||
|
||||
bool UseTrailingReturnTypeCheck::keepSpecifiers(
|
||||
std::string &ReturnType, std::string &Auto, SourceRange ReturnTypeCVRange,
|
||||
const FunctionDecl &F, const FriendDecl *Fr, const ASTContext &Ctx,
|
||||
const SourceManager &SM, const LangOptions &LangOpts) {
|
||||
// Check if there are specifiers inside the return type. E.g. unsigned
|
||||
// inline int.
|
||||
const auto *M = dyn_cast<CXXMethodDecl>(&F);
|
||||
if (!F.isConstexpr() && !F.isInlineSpecified() &&
|
||||
F.getStorageClass() != SC_Extern && F.getStorageClass() != SC_Static &&
|
||||
!Fr && !(M && M->isVirtualAsWritten()))
|
||||
return true;
|
||||
|
||||
// Tokenize return type. If it contains macros which contain a mix of
|
||||
// qualifiers, specifiers and types, give up.
|
||||
llvm::Optional<SmallVector<ClassifiedToken, 8>> MaybeTokens =
|
||||
classifyTokensBeforeFunctionName(F, Ctx, SM, LangOpts);
|
||||
if (!MaybeTokens)
|
||||
return false;
|
||||
|
||||
// Find specifiers, remove them from the return type, add them to 'auto'.
|
||||
unsigned int ReturnTypeBeginOffset =
|
||||
SM.getDecomposedLoc(ReturnTypeCVRange.getBegin()).second;
|
||||
size_t InitialAutoLength = Auto.size();
|
||||
unsigned int DeletedChars = 0;
|
||||
for (ClassifiedToken CT : *MaybeTokens) {
|
||||
if (SM.isBeforeInTranslationUnit(CT.T.getLocation(),
|
||||
ReturnTypeCVRange.getBegin()) ||
|
||||
SM.isBeforeInTranslationUnit(ReturnTypeCVRange.getEnd(),
|
||||
CT.T.getLocation()))
|
||||
continue;
|
||||
if (!CT.isSpecifier)
|
||||
continue;
|
||||
|
||||
// Add the token to 'auto' and remove it from the return type, including
|
||||
// any whitespace following the token.
|
||||
unsigned int TOffset = SM.getDecomposedLoc(CT.T.getLocation()).second;
|
||||
assert(TOffset >= ReturnTypeBeginOffset &&
|
||||
"Token location must be after the beginning of the return type");
|
||||
unsigned int TOffsetInRT = TOffset - ReturnTypeBeginOffset - DeletedChars;
|
||||
unsigned int TLengthWithWS = CT.T.getLength();
|
||||
while (TOffsetInRT + TLengthWithWS < ReturnType.size() &&
|
||||
std::isspace(ReturnType[TOffsetInRT + TLengthWithWS]))
|
||||
TLengthWithWS++;
|
||||
std::string Specifier = ReturnType.substr(TOffsetInRT, TLengthWithWS);
|
||||
if (!std::isspace(Specifier.back()))
|
||||
Specifier.push_back(' ');
|
||||
Auto.insert(Auto.size() - InitialAutoLength, Specifier);
|
||||
ReturnType.erase(TOffsetInRT, TLengthWithWS);
|
||||
DeletedChars += TLengthWithWS;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::registerMatchers(MatchFinder *Finder) {
|
||||
if (!getLangOpts().CPlusPlus11)
|
||||
return;
|
||||
|
||||
auto F = functionDecl(unless(anyOf(hasTrailingReturn(), returns(voidType()),
|
||||
returns(autoType()), cxxConversionDecl(),
|
||||
cxxMethodDecl(isImplicit()))))
|
||||
.bind("Func");
|
||||
|
||||
Finder->addMatcher(F, this);
|
||||
Finder->addMatcher(friendDecl(hasDescendant(F)).bind("Friend"), this);
|
||||
}
|
||||
|
||||
void UseTrailingReturnTypeCheck::registerPPCallbacks(
|
||||
const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {
|
||||
this->PP = PP;
|
||||
}
|
||||
|
||||
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");
|
||||
const auto *Fr = Result.Nodes.getNodeAs<FriendDecl>("Friend");
|
||||
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() ||
|
||||
F->getDeclaredReturnType()->getAs<DecltypeType>() != nullptr) {
|
||||
diag(F->getLocation(), Message);
|
||||
return;
|
||||
}
|
||||
|
||||
const ASTContext &Ctx = *Result.Context;
|
||||
const SourceManager &SM = *Result.SourceManager;
|
||||
const LangOptions &LangOpts = getLangOpts();
|
||||
|
||||
const TypeSourceInfo *TSI = F->getTypeSourceInfo();
|
||||
if (!TSI)
|
||||
return;
|
||||
|
||||
FunctionTypeLoc FTL =
|
||||
TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>();
|
||||
if (!FTL) {
|
||||
// FIXME: This may happen if we have __attribute__((...)) on the function.
|
||||
// We abort for now. Remove this when the function type location gets
|
||||
// available in clang.
|
||||
diag(F->getLocation(), Message);
|
||||
return;
|
||||
}
|
||||
|
||||
SourceLocation InsertionLoc =
|
||||
findTrailingReturnTypeSourceLocation(*F, FTL, Ctx, SM, LangOpts);
|
||||
if (InsertionLoc.isInvalid()) {
|
||||
diag(F->getLocation(), Message);
|
||||
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;
|
||||
|
||||
// Check if unqualified names in the return type conflict with other entities
|
||||
// after the rewrite.
|
||||
// FIXME: this could be done better, by performing a lookup of all
|
||||
// unqualified names in the return type in the scope of the function. If the
|
||||
// lookup finds a different entity than the original entity identified by the
|
||||
// name, then we can either not perform a rewrite or explicitely qualify the
|
||||
// entity. Such entities could be function parameter names, (inherited) class
|
||||
// members, template parameters, etc.
|
||||
UnqualNameVisitor UNV{*F, SM};
|
||||
UNV.TraverseTypeLoc(FTL.getReturnLoc());
|
||||
if (UNV.Collision) {
|
||||
diag(F->getLocation(), Message);
|
||||
return;
|
||||
}
|
||||
|
||||
SourceLocation ReturnTypeEnd =
|
||||
Lexer::getLocForEndOfToken(ReturnTypeCVRange.getEnd(), 0, SM, LangOpts);
|
||||
StringRef CharAfterReturnType = Lexer::getSourceText(
|
||||
CharSourceRange::getCharRange(ReturnTypeEnd,
|
||||
ReturnTypeEnd.getLocWithOffset(1)),
|
||||
SM, LangOpts);
|
||||
bool NeedSpaceAfterAuto =
|
||||
CharAfterReturnType.empty() || !std::isspace(CharAfterReturnType[0]);
|
||||
|
||||
std::string Auto = NeedSpaceAfterAuto ? "auto " : "auto";
|
||||
std::string ReturnType = tooling::fixit::getText(ReturnTypeCVRange, Ctx);
|
||||
keepSpecifiers(ReturnType, Auto, ReturnTypeCVRange, *F, Fr, Ctx, SM,
|
||||
LangOpts);
|
||||
|
||||
diag(F->getLocation(), Message)
|
||||
<< FixItHint::CreateReplacement(ReturnTypeCVRange, Auto)
|
||||
<< FixItHint::CreateInsertion(InsertionLoc, " -> " + ReturnType);
|
||||
}
|
||||
|
||||
} // namespace modernize
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -0,0 +1,62 @@
|
|||
//===--- UseTrailingReturnTypeCheck.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_USETRAILINGRETURNTYPECHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USETRAILINGRETURNTYPECHECK_H
|
||||
|
||||
#include "../ClangTidy.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace modernize {
|
||||
|
||||
struct ClassifiedToken {
|
||||
Token T;
|
||||
bool isQualifier;
|
||||
bool isSpecifier;
|
||||
};
|
||||
|
||||
/// 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-type-return.html
|
||||
class UseTrailingReturnTypeCheck : public ClangTidyCheck {
|
||||
public:
|
||||
UseTrailingReturnTypeCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
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;
|
||||
|
||||
private:
|
||||
Preprocessor *PP = nullptr;
|
||||
|
||||
SourceLocation findTrailingReturnTypeSourceLocation(
|
||||
const FunctionDecl &F, const FunctionTypeLoc &FTL, const ASTContext &Ctx,
|
||||
const SourceManager &SM, const LangOptions &LangOpts);
|
||||
llvm::Optional<SmallVector<ClassifiedToken, 8>>
|
||||
classifyTokensBeforeFunctionName(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);
|
||||
bool keepSpecifiers(std::string &ReturnType, std::string &Auto,
|
||||
SourceRange ReturnTypeCVRange, const FunctionDecl &F,
|
||||
const FriendDecl *Fr, const ASTContext &Ctx,
|
||||
const SourceManager &SM, const LangOptions &LangOpts);
|
||||
};
|
||||
|
||||
} // namespace modernize
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USETRAILINGRETURNTYPECHECK_H
|
|
@ -151,6 +151,14 @@ Improvements to clang-tidy
|
|||
finds and replaces cases that match the pattern ``var &&
|
||||
isa<X>(var)``, where ``var`` is evaluated twice.
|
||||
|
||||
- New :doc:`modernize-use-trailing-type-return
|
||||
<clang-tidy/checks/modernize-use-trailing-type-return>` check.
|
||||
|
||||
Rewrites function signatures to use a trailing return type.
|
||||
|
||||
Improvements to include-fixer
|
||||
-----------------------------
|
||||
|
||||
- New :doc:`openmp-exception-escape
|
||||
<clang-tidy/checks/openmp-exception-escape>` check.
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@ Clang-Tidy Checks
|
|||
modernize-use-noexcept
|
||||
modernize-use-nullptr
|
||||
modernize-use-override
|
||||
modernize-use-trailing-return-type
|
||||
modernize-use-transparent-functors
|
||||
modernize-use-uncaught-exceptions
|
||||
modernize-use-using
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
.. title:: clang-tidy - modernize-use-trailing-return-type
|
||||
|
||||
modernize-use-trailing-return-type
|
||||
==================================
|
||||
|
||||
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
|
||||
* decltype, when it is the top level expression
|
||||
|
||||
Unqualified names in the return type might erroneously refer to different entities after the rewrite.
|
||||
Preventing such errors requires a full lookup of all unqualified names present in the return type in the scope of the trailing return type location.
|
||||
This location includes e.g. function parameter names and members of the enclosing class (including all inherited classes).
|
||||
Such a lookup is currently not implemented.
|
||||
|
||||
Given the following piece of code
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
struct Object { long long value; };
|
||||
Object f(unsigned Object) { return {Object * 2}; }
|
||||
class CC {
|
||||
int Object;
|
||||
struct Object m();
|
||||
};
|
||||
Object CC::m() { return {0}; }
|
||||
|
||||
a careless rewrite would produce the following output:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
struct Object { long long value; };
|
||||
auto f(unsigned Object) -> Object { return {Object * 2}; } // error
|
||||
class CC {
|
||||
int Object;
|
||||
auto m() -> struct Object;
|
||||
};
|
||||
auto CC::m() -> Object { return {0}; } // error
|
||||
|
||||
This code fails to compile because the Object in the context of f refers to the equally named function parameter.
|
||||
Similarly, the Object in the context of m refers to the equally named class member.
|
||||
The check can currently only detect a clash with a function parameter name.
|
|
@ -0,0 +1,563 @@
|
|||
// RUN: %check_clang_tidy %s modernize-use-trailing-return-type %t -- -- --std=c++14 -fdeclspec
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
class vector;
|
||||
|
||||
template <typename T, int N>
|
||||
class array;
|
||||
|
||||
class string;
|
||||
|
||||
template <typename T>
|
||||
auto declval() -> T;
|
||||
}
|
||||
|
||||
//
|
||||
// Functions
|
||||
//
|
||||
|
||||
int f();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto f() -> int;{{$}}
|
||||
int ((f))();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}auto a5{{$}}
|
||||
(int arg);
|
||||
// CHECK-FIXES: {{^}}(int arg) -> int;{{$}}
|
||||
const
|
||||
int
|
||||
*
|
||||
a7
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
()
|
||||
// CHECK-FIXES: {{^}}() -> const{{$}}
|
||||
// CHECK-FIXES: {{^}}int{{$}}
|
||||
// CHECK-FIXES: {{^}}*{{$}}
|
||||
;
|
||||
|
||||
int*a7(int arg);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto a7(int arg) -> int*;{{$}}
|
||||
template<template <typename> class C>
|
||||
C<int>a8(int arg);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto a8(int arg) -> C<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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}inline auto d3(int arg) noexcept(true) -> int;{{$}}
|
||||
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-type]
|
||||
// CHECK-FIXES: {{^}}inline auto d4(int arg) -> int try { } catch(...) { }{{$}}
|
||||
int d5(int arg) throw();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto d5(int arg) throw() -> int;{{$}}
|
||||
static int d6(int arg);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto d6(int arg) -> int;{{$}}
|
||||
int static d6(int arg);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto static d6(int arg) -> int;{{$}}
|
||||
unsigned static int d7(int arg);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto d7(int arg) -> unsigned int;{{$}}
|
||||
const long static int volatile constexpr unsigned inline long d8(int arg);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:63: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static constexpr inline auto d8(int arg) -> const long int volatile unsigned long;{{$}}
|
||||
int constexpr d9();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto constexpr d9() -> int;{{$}}
|
||||
inline int constexpr d10();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}inline auto constexpr d10() -> int;{{$}}
|
||||
unsigned constexpr int d11();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}constexpr auto d11() -> unsigned int;{{$}}
|
||||
unsigned extern int d13();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}extern auto d13() -> unsigned int;{{$}}
|
||||
int static& d14();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto d14() -> int &;{{$}}
|
||||
class DDD {
|
||||
int friend unsigned m1();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} friend auto m1() -> int unsigned;{{$}}
|
||||
int friend unsigned m1() { return 0; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} friend auto m1() -> int unsigned { return 0; }{{$}}
|
||||
const long int friend volatile constexpr unsigned inline long m2();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:67: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} friend constexpr inline auto m2() -> const long int volatile unsigned long;{{$}}
|
||||
int virtual unsigned m3();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} virtual auto m3() -> int unsigned;{{$}}
|
||||
template <typename T>
|
||||
int friend unsigned m4();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} friend auto m4() -> int unsigned;{{$}}
|
||||
};
|
||||
|
||||
//
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}auto N::e1() -> int {}{{$}}
|
||||
|
||||
//
|
||||
// Functions with unsupported return types
|
||||
//
|
||||
int (*e3())(double);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}int (*e3())(double);{{$}}
|
||||
struct A;
|
||||
int A::* e5();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}int A::* e5();{{$}}
|
||||
int std::vector<std::string>::* e6();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}int std::vector<std::string>::* e6();{{$}}
|
||||
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-type]
|
||||
// CHECK-FIXES: {{^}}int (std::vector<std::string>::*e7())(double);{{$}}
|
||||
|
||||
//
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}inline auto e2() -> std::vector<std::string> const volatile;{{$}}
|
||||
int* e8();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto e8() -> int*;{{$}}
|
||||
static const char* e9(void* user_data);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto e9(void* user_data) -> const char*;{{$}}
|
||||
static const char* const e10(void* user_data);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto e10(void* user_data) -> const char* const;{{$}}
|
||||
static const char** volatile * const & e11(void* user_data);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto e11(void* user_data) -> const char** volatile * const &;{{$}}
|
||||
static const char* const * const * const e12(void* user_data);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}static auto e12(void* user_data) -> const char* const * const * const;{{$}}
|
||||
struct A e13();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto e13() -> struct A;{{$}}
|
||||
|
||||
//
|
||||
// decltype (unsupported if top level expression)
|
||||
//
|
||||
|
||||
decltype(1 + 2) dec1() { return 1 + 2; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// TODO: source range of DecltypeTypeLoc not yet implemented
|
||||
// _HECK-FIXES: {{^}}auto dec1() -> decltype(1 + 2) { return 1 + 2; }{{$}}
|
||||
template <typename F, typename T>
|
||||
decltype(std::declval<F>(std::declval<T>)) dec2(F f, T t) { return f(t); }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// TODO: source range of DecltypeTypeLoc not yet implemented
|
||||
// _HECK-FIXES: {{^}}auto dec2(F f, T t) -> decltype(std::declval<F>(std::declval<T>)) { return f(t); }{{$}}
|
||||
template <typename T>
|
||||
typename decltype(std::declval<T>())::value_type dec3();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:50: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto dec3() -> typename decltype(std::declval<T>())::value_type;{{$}}
|
||||
template <typename T>
|
||||
decltype(std::declval<T>())* dec4();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto dec4() -> decltype(std::declval<T>())*;{{$}}
|
||||
|
||||
//
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}} auto base8(int, bool b) const volatile & -> double = delete;{{$}}
|
||||
|
||||
virtual const char * base9() const noexcept { return ""; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} virtual auto base9() const noexcept -> const char * { return ""; }{{$}}
|
||||
};
|
||||
|
||||
double B::base1(int, bool b) {}
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}} virtual auto base3() const -> float override final { }{{$}}
|
||||
|
||||
const char * base9() const noexcept override { return ""; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto base9() const noexcept -> const char * override { return ""; }{{$}}
|
||||
|
||||
int f2() __restrict;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto f2() __restrict -> int;{{$}}
|
||||
|
||||
volatile int* __restrict f3() const __restrict noexcept;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto f3() const __restrict noexcept -> volatile int* __restrict;{{$}}
|
||||
};
|
||||
|
||||
//
|
||||
// Functions with attributes
|
||||
//
|
||||
|
||||
int g1() [[asdf]];
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}auto g2 {{[[][[]}}noreturn{{[]][]]}} () -> int;{{$}}
|
||||
int unsigned g3() __attribute__((cdecl)); // FunctionTypeLoc is null.
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
int unsigned __attribute__((cdecl)) g3() ; // FunctionTypeLoc is null.
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
__attribute__((cdecl)) int unsigned g3() ; // FunctionTypeLoc is null.
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
|
||||
//
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}{{[[][[]}}maybe_unused{{[]][]]}} auto t1(Container& C) noexcept -> typename Container::value_type const volatile&&;{{$}}
|
||||
template <typename T>
|
||||
class BB {
|
||||
using type = int;
|
||||
|
||||
template <typename U>
|
||||
typename BB<U>::type m1();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto m1() -> typename BB<U>::type;{{$}}
|
||||
};
|
||||
|
||||
//
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// 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-type]
|
||||
// CHECK-FIXES: {{^}}auto h3() -> CONST int;{{$}}
|
||||
#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-type]
|
||||
// CHECK-FIXES: {{^}}ALWAYS_INLINE DLL_EXPORT auto h4() -> int;{{$}}
|
||||
#define DEPRECATED __attribute__((deprecated))
|
||||
int h5() DEPRECATED;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto h5() -> int DEPRECATED;{{$}}
|
||||
int DEPRECATED h5();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto DEPRECATED h5() -> int;{{$}}
|
||||
DEPRECATED int h5();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}DEPRECATED auto h5() -> int;{{$}}
|
||||
[[noreturn]] [[nodiscard]] DEPRECATED DLL_EXPORT int h6 [[deprecated]] ();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}{{[[][[]}}noreturn{{[]][]]}} {{[[][[]}}nodiscard{{[]][]]}} DEPRECATED DLL_EXPORT auto h6 {{[[][[]}}deprecated{{[]][]]}} () -> int;{{$}}
|
||||
#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-type]
|
||||
// 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-type]
|
||||
#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-type]
|
||||
#define DLL_EXPORT_const __declspec(dllexport) const
|
||||
DLL_EXPORT_const int h7();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
#define DLL_EXPORT_CONST __declspec(dllexport) CONST
|
||||
DLL_EXPORT_CONST int h7();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
|
||||
template <typename T>
|
||||
using Real = T;
|
||||
#define PRECISION float
|
||||
Real<PRECISION> h8() { return 0.; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto h8() -> Real<PRECISION> { return 0.; }{{$}}
|
||||
|
||||
#define MAYBE_UNUSED_MACRO [[maybe_unused]]
|
||||
template <typename Container>
|
||||
MAYBE_UNUSED_MACRO typename Container::value_type const volatile** const h9(Container& C) noexcept;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:74: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}MAYBE_UNUSED_MACRO auto h9(Container& C) noexcept -> typename Container::value_type const volatile** const;{{$}}
|
||||
|
||||
#define NOEXCEPT noexcept
|
||||
int h9(int arg) NOEXCEPT;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto h9(int arg) NOEXCEPT -> int;{{$}}
|
||||
#define STATIC_INT static int
|
||||
STATIC_INT h10();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
#define UNSIGNED_STATIC_INT unsigned static int
|
||||
UNSIGNED_STATIC_INT h11();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
#define STATIC static
|
||||
unsigned STATIC int h11();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}STATIC auto h11() -> unsigned int;{{$}}
|
||||
#define STATIC_CONSTEXPR static constexpr
|
||||
unsigned STATIC_CONSTEXPR int h12();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}STATIC_CONSTEXPR auto h12() -> unsigned int;{{$}}
|
||||
#define STATIC_CONSTEXPR_LONG static constexpr long
|
||||
unsigned STATIC_CONSTEXPR_LONG int h13();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
DEPRECATED const int& h14();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}DEPRECATED auto h14() -> const int&;{{$}}
|
||||
DEPRECATED const long static volatile unsigned& h15();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}DEPRECATED static auto h15() -> const long volatile unsigned&;{{$}}
|
||||
#define WRAP(x) x
|
||||
WRAP(const) int& h16();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
WRAP(CONST) int& h16();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
#define CONCAT(a, b) a##b
|
||||
CONCAT(con, st) int& h16();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
DEPRECATED const UNSIGNED& h17();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}DEPRECATED auto h17() -> const UNSIGNED&;{{$}}
|
||||
DEPRECATED CONST UNSIGNED STATIC& h17();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}DEPRECATED STATIC auto h17() -> CONST UNSIGNED &;{{$}}
|
||||
#define CONST_CAT con##st
|
||||
CONST_CAT int& h18();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto h18() -> CONST_CAT int&;{{$}}
|
||||
#define CONST_F_MACRO WRAP(CONST_CAT)
|
||||
CONST_F_MACRO int& h18();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto h18() -> CONST_F_MACRO int&;{{$}}
|
||||
|
||||
//
|
||||
// Name collisions
|
||||
//
|
||||
struct Object { long long value; };
|
||||
|
||||
Object j1(unsigned Object) { return {Object * 2}; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}Object j1(unsigned Object) { return {Object * 2}; }{{$}}
|
||||
::Object j1(unsigned Object);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto j1(unsigned Object) -> ::Object;{{$}}
|
||||
const Object& j2(unsigned a, int b, char Object, long l);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}const Object& j2(unsigned a, int b, char Object, long l);{{$}}
|
||||
const struct Object& j2(unsigned a, int b, char Object, long l);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto j2(unsigned a, int b, char Object, long l) -> const struct Object&;{{$}}
|
||||
std::vector<Object> j3(unsigned Object);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}std::vector<Object> j3(unsigned Object);{{$}}
|
||||
std::vector<const Object> j7(unsigned Object);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}std::vector<const Object> j7(unsigned Object);{{$}}
|
||||
std::vector<Object> j4(unsigned vector);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto j4(unsigned vector) -> std::vector<Object>;{{$}}
|
||||
std::vector<::Object> j4(unsigned vector);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto j4(unsigned vector) -> std::vector<::Object>;{{$}}
|
||||
std::vector<struct Object> j4(unsigned vector);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto j4(unsigned vector) -> std::vector<struct Object>;{{$}}
|
||||
std::vector<Object> j4(unsigned Vector);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto j4(unsigned Vector) -> std::vector<Object>;{{$}}
|
||||
using std::vector;
|
||||
vector<Object> j5(unsigned vector);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}vector<Object> j5(unsigned vector);{{$}}
|
||||
constexpr auto Size = 5;
|
||||
std::array<int, Size> j6(unsigned Size);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}std::array<int, Size> j6(unsigned Size);{{$}}
|
||||
std::array<decltype(Size), (Size * 2) + 1> j8(unsigned Size);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}std::array<decltype(Size), (Size * 2) + 1> j8(unsigned Size);{{$}}
|
||||
|
||||
class CC {
|
||||
int Object;
|
||||
struct Object m();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto m() -> struct Object;{{$}}
|
||||
};
|
||||
Object CC::m() { return {0}; }
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto CC::m() -> Object { return {0}; }{{$}}
|
||||
class DD : public CC {
|
||||
::Object g();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}} auto g() -> ::Object;{{$}}
|
||||
};
|
||||
Object DD::g() {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use a trailing return type for this function [modernize-use-trailing-return-type]
|
||||
// CHECK-FIXES: {{^}}auto DD::g() -> Object {{{$}}
|
||||
return {0};
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Samples which do not trigger the check
|
||||
//
|
||||
|
||||
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;
|
||||
|
||||
auto ff();
|
||||
decltype(auto) fff();
|
||||
|
||||
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 {};
|
Loading…
Reference in New Issue