Index: clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt @@ -6,6 +6,7 @@ MakeUniqueCheck.cpp ModernizeTidyModule.cpp PassByValueCheck.cpp + RedundantVoidArgCheck.cpp ReplaceAutoPtrCheck.cpp ShrinkToFitCheck.cpp UseAutoCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -13,6 +13,7 @@ #include "LoopConvertCheck.h" #include "MakeUniqueCheck.h" #include "PassByValueCheck.h" +#include "RedundantVoidArgCheck.h" #include "ReplaceAutoPtrCheck.h" #include "ShrinkToFitCheck.h" #include "UseAutoCheck.h" @@ -32,6 +33,8 @@ CheckFactories.registerCheck("modernize-loop-convert"); CheckFactories.registerCheck("modernize-make-unique"); CheckFactories.registerCheck("modernize-pass-by-value"); + CheckFactories.registerCheck( + "modernize-redundant-void-arg"); CheckFactories.registerCheck( "modernize-replace-auto-ptr"); CheckFactories.registerCheck("modernize-shrink-to-fit"); Index: clang-tools-extra/trunk/clang-tidy/modernize/RedundantVoidArgCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/RedundantVoidArgCheck.h +++ clang-tools-extra/trunk/clang-tidy/modernize/RedundantVoidArgCheck.h @@ -0,0 +1,76 @@ +//===--- RedundantVoidArgCheck.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_REDUNDANT_VOID_ARG_CHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H + +#include "../ClangTidy.h" +#include "clang/Lex/Token.h" + +#include + +namespace clang { +namespace tidy { +namespace modernize { + +/// \brief Find and remove redundant void argument lists. +/// +/// Examples: +/// `int f(void);` becomes `int f();` +/// `int (*f(void))(void);` becomes `int (*f())();` +/// `typedef int (*f_t(void))(void);` becomes `typedef int (*f_t())();` +/// `void (C::*p)(void);` becomes `void (C::*p)();` +/// `C::C(void) {}` becomes `C::C() {}` +/// `C::~C(void) {}` becomes `C::~C() {}` +/// +class RedundantVoidArgCheck : public ClangTidyCheck { +public: + RedundantVoidArgCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void processFunctionDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const FunctionDecl *Function); + + void processTypedefDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const TypedefDecl *Typedef); + + void processFieldDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const FieldDecl *Member); + + void processVarDecl(const ast_matchers::MatchFinder::MatchResult &Result, + const VarDecl *Var); + + void + processNamedCastExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const CXXNamedCastExpr *NamedCast); + + void + processExplicitCastExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const ExplicitCastExpr *ExplicitCast); + + void processLambdaExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const LambdaExpr *Lambda); + + void + removeVoidArgumentTokens(const ast_matchers::MatchFinder::MatchResult &Result, + SourceRange Range, StringRef GrammarLocation); + + void removeVoidToken(Token VoidToken, StringRef Diagnostic); +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H Index: clang-tools-extra/trunk/clang-tidy/modernize/RedundantVoidArgCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/RedundantVoidArgCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/modernize/RedundantVoidArgCheck.cpp @@ -0,0 +1,254 @@ +//===- RedundantVoidArgCheck.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 "RedundantVoidArgCheck.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { + +namespace { + +// Determine if the given QualType is a nullary function or pointer to same. +bool protoTypeHasNoParms(QualType QT) { + if (auto PT = QT->getAs()) { + QT = PT->getPointeeType(); + } + if (auto *MPT = QT->getAs()) { + QT = MPT->getPointeeType(); + } + if (auto FP = QT->getAs()) { + return FP->getNumParams() == 0; + } + return false; +} + +const char FunctionId[] = "function"; +const char TypedefId[] = "typedef"; +const char FieldId[] = "field"; +const char VarId[] = "var"; +const char NamedCastId[] = "named-cast"; +const char CStyleCastId[] = "c-style-cast"; +const char ExplicitCastId[] = "explicit-cast"; +const char LambdaId[] = "lambda"; + +} // namespace + +namespace tidy { +namespace modernize { + +void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(functionDecl(isExpansionInMainFile(), parameterCountIs(0), + unless(isImplicit()), + unless(isExternC())).bind(FunctionId), + this); + Finder->addMatcher(typedefDecl(isExpansionInMainFile()).bind(TypedefId), + this); + auto ParenFunctionType = parenType(innerType(functionType())); + auto PointerToFunctionType = pointee(ParenFunctionType); + auto FunctionOrMemberPointer = + anyOf(hasType(pointerType(PointerToFunctionType)), + hasType(memberPointerType(PointerToFunctionType))); + Finder->addMatcher( + fieldDecl(isExpansionInMainFile(), FunctionOrMemberPointer).bind(FieldId), + this); + Finder->addMatcher( + varDecl(isExpansionInMainFile(), FunctionOrMemberPointer).bind(VarId), + this); + auto CastDestinationIsFunction = + hasDestinationType(pointsTo(ParenFunctionType)); + Finder->addMatcher( + cStyleCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(CStyleCastId), + this); + Finder->addMatcher( + cxxStaticCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(NamedCastId), + this); + Finder->addMatcher( + cxxReinterpretCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(NamedCastId), + this); + Finder->addMatcher(cxxConstCastExpr(isExpansionInMainFile(), + CastDestinationIsFunction).bind(NamedCastId), + this); + Finder->addMatcher(lambdaExpr(isExpansionInMainFile()).bind(LambdaId), this); +} + +void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) { + if (!Result.Context->getLangOpts().CPlusPlus) { + return; + } + + const BoundNodes &Nodes = Result.Nodes; + if (const auto *Function = Nodes.getNodeAs(FunctionId)) { + processFunctionDecl(Result, Function); + } else if (const auto *Typedef = Nodes.getNodeAs(TypedefId)) { + processTypedefDecl(Result, Typedef); + } else if (const auto *Member = Nodes.getNodeAs(FieldId)) { + processFieldDecl(Result, Member); + } else if (const auto *Var = Nodes.getNodeAs(VarId)) { + processVarDecl(Result, Var); + } else if (const auto *NamedCast = + Nodes.getNodeAs(NamedCastId)) { + processNamedCastExpr(Result, NamedCast); + } else if (const auto *CStyleCast = + Nodes.getNodeAs(CStyleCastId)) { + processExplicitCastExpr(Result, CStyleCast); + } else if (const auto *ExplicitCast = + Nodes.getNodeAs(ExplicitCastId)) { + processExplicitCastExpr(Result, ExplicitCast); + } else if (const auto *Lambda = Nodes.getNodeAs(LambdaId)) { + processLambdaExpr(Result, Lambda); + } +} + +void RedundantVoidArgCheck::processFunctionDecl( + const MatchFinder::MatchResult &Result, const FunctionDecl *Function) { + SourceLocation Start = Function->getLocStart(); + if (Function->isThisDeclarationADefinition()) { + SourceLocation BeforeBody = + Function->getBody()->getLocStart().getLocWithOffset(-1); + removeVoidArgumentTokens(Result, SourceRange(Start, BeforeBody), + "function definition"); + } else { + removeVoidArgumentTokens(Result, Function->getSourceRange(), + "function declaration"); + } +} + +void RedundantVoidArgCheck::removeVoidArgumentTokens( + const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range, + StringRef GrammarLocation) { + std::string DeclText = + Lexer::getSourceText(CharSourceRange::getTokenRange(Range), + *Result.SourceManager, + Result.Context->getLangOpts()).str(); + Lexer PrototypeLexer(Range.getBegin(), Result.Context->getLangOpts(), + DeclText.data(), DeclText.data(), + DeclText.data() + DeclText.size()); + enum TokenState { + NothingYet, + SawLeftParen, + SawVoid, + }; + TokenState State = NothingYet; + Token VoidToken; + Token ProtoToken; + std::string Diagnostic = + ("redundant void argument list in " + GrammarLocation).str(); + + while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) { + switch (State) { + case NothingYet: + if (ProtoToken.is(tok::TokenKind::l_paren)) { + State = SawLeftParen; + } + break; + case SawLeftParen: + if (ProtoToken.is(tok::TokenKind::raw_identifier) && + ProtoToken.getRawIdentifier() == "void") { + State = SawVoid; + VoidToken = ProtoToken; + } else { + State = NothingYet; + } + break; + case SawVoid: + State = NothingYet; + if (ProtoToken.is(tok::TokenKind::r_paren)) { + removeVoidToken(VoidToken, Diagnostic); + } else if (ProtoToken.is(tok::TokenKind::l_paren)) { + State = SawLeftParen; + } + break; + } + } + + if (State == SawVoid && ProtoToken.is(tok::TokenKind::r_paren)) { + removeVoidToken(VoidToken, Diagnostic); + } +} + +void RedundantVoidArgCheck::removeVoidToken(Token VoidToken, + StringRef Diagnostic) { + SourceLocation VoidLoc(VoidToken.getLocation()); + auto VoidRange = + CharSourceRange::getTokenRange(VoidLoc, VoidLoc.getLocWithOffset(3)); + diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange); +} + +void RedundantVoidArgCheck::processTypedefDecl( + const MatchFinder::MatchResult &Result, const TypedefDecl *Typedef) { + if (protoTypeHasNoParms(Typedef->getUnderlyingType())) { + removeVoidArgumentTokens(Result, Typedef->getSourceRange(), "typedef"); + } +} + +void RedundantVoidArgCheck::processFieldDecl( + const MatchFinder::MatchResult &Result, const FieldDecl *Member) { + if (protoTypeHasNoParms(Member->getType())) { + removeVoidArgumentTokens(Result, Member->getSourceRange(), + "field declaration"); + } +} + +void RedundantVoidArgCheck::processVarDecl( + const MatchFinder::MatchResult &Result, const VarDecl *Var) { + if (protoTypeHasNoParms(Var->getType())) { + SourceLocation Begin = Var->getLocStart(); + if (Var->hasInit()) { + SourceLocation InitStart = + Result.SourceManager->getExpansionLoc(Var->getInit()->getLocStart()) + .getLocWithOffset(-1); + removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart), + "variable declaration with initializer"); + } else { + removeVoidArgumentTokens(Result, Var->getSourceRange(), + "variable declaration"); + } + } +} + +void RedundantVoidArgCheck::processNamedCastExpr( + const MatchFinder::MatchResult &Result, const CXXNamedCastExpr *NamedCast) { + if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) { + removeVoidArgumentTokens( + Result, + NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(), + "named cast"); + } +} + +void RedundantVoidArgCheck::processExplicitCastExpr( + const MatchFinder::MatchResult &Result, + const ExplicitCastExpr *ExplicitCast) { + if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten())) { + removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(), + "cast expression"); + } +} + +void RedundantVoidArgCheck::processLambdaExpr( + const MatchFinder::MatchResult &Result, const LambdaExpr *Lambda) { + if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 && + Lambda->hasExplicitParameters()) { + SourceLocation Begin = + Lambda->getIntroducerRange().getEnd().getLocWithOffset(1); + SourceLocation End = Lambda->getBody()->getLocStart().getLocWithOffset(-1); + removeVoidArgumentTokens(Result, SourceRange(Begin, End), + "lambda expression"); + } +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/test/clang-tidy/modernize-redundant-void-arg.c =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-redundant-void-arg.c +++ clang-tools-extra/trunk/test/clang-tidy/modernize-redundant-void-arg.c @@ -0,0 +1,58 @@ +// RUN: clang-tidy -checks=-*,modernize-redundant-void-arg %s -- -x c | count 0 + +#include + +extern int i; + +int foo2() { + return 0; +} + +int j = 1; + +int foo(void) { + return 0; +} + +typedef unsigned int my_uint; + +typedef void my_void; + +// A function taking void and returning a pointer to function taking void +// and returning int. +int (*returns_fn_void_int(void))(void); + +typedef int (*returns_fn_void_int_t(void))(void); + +int (*returns_fn_void_int(void))(void) { + return NULL; +} + +// A function taking void and returning a pointer to a function taking void +// and returning a pointer to a function taking void and returning void. +void (*(*returns_fn_returns_fn_void_void(void))(void))(void); + +typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void); + +void (*(*returns_fn_returns_fn_void_void(void))(void))(void) { + return NULL; +} + +void bar() { + int i; + int *pi = NULL; + void *pv = (void *) pi; + float f; + float *fi; + double d; + double *pd; +} + +void (*f1)(void); +void (*f2)(void) = NULL; +void (*f3)(void) = bar; +void (*fa)(); +void (*fb)() = NULL; +void (*fc)() = bar; + +typedef void (function_ptr)(void); Index: clang-tools-extra/trunk/test/clang-tidy/modernize-redundant-void-arg.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-redundant-void-arg.cpp +++ clang-tools-extra/trunk/test/clang-tidy/modernize-redundant-void-arg.cpp @@ -0,0 +1,419 @@ +// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t + +#include + +int foo(); + +void bar(); + +void bar2(); + +extern "C" void ecfoo(void); + +extern "C" void ecfoo(void) { +} + +extern int i; + +int j = 1; + +int foo(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg] +// CHECK-FIXES: {{^}}int foo() {{{$}} + return 0; +} + +typedef unsigned int my_uint; + +typedef void my_void; + +// A function taking void and returning a pointer to function taking void +// and returning int. +int (*returns_fn_void_int(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function declaration +// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function declaration +// CHECK-FIXES: {{^}}int (*returns_fn_void_int())();{{$}} + +typedef int (*returns_fn_void_int_t(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:37: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-2]]:44: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef int (*returns_fn_void_int_t())();{{$}} + +int (*returns_fn_void_int(void))(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: {{.*}} in function definition +// CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}int (*returns_fn_void_int())() {{{$}} + return nullptr; +} + +// A function taking void and returning a pointer to a function taking void +// and returning a pointer to a function taking void and returning void. +void (*(*returns_fn_returns_fn_void_void(void))(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function declaration +// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function declaration +// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function declaration +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())();{{$}} + +typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void); +// CHECK-MESSAGES: :[[@LINE-1]]:52: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-2]]:59: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-3]]:66: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef void (*(*returns_fn_returns_fn_void_void_t())())();{{$}} + +void (*(*returns_fn_returns_fn_void_void(void))(void))(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:42: warning: {{.*}} in function definition +// CHECK-MESSAGES: :[[@LINE-2]]:49: warning: {{.*}} in function definition +// CHECK-MESSAGES: :[[@LINE-3]]:56: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void())())() {{{$}} + return nullptr; +} + +void bar(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}void bar() {{{$}} +} + +void op_fn(int i) { +} + +class gronk { +public: + gronk(); + ~gronk(); + + void foo(); + void bar(); + void bar2 + (); + void operation(int i) { } + +private: + int m_i; + int *m_pi; + float m_f; + float *m_pf; + double m_d; + double *m_pd; + + void (*f1)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in field declaration + // CHECK-FIXES: {{^ }}void (*f1)();{{$}} + + void (*op)(int i); + + void (gronk::*p1)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in field declaration + // CHECK-FIXES: {{^ }}void (gronk::*p1)();{{$}} + + int (gronk::*p_mi); + + void (gronk::*p2)(int); + + void (*(*returns_fn_returns_fn_void_void(void))(void))(void); + // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in function declaration + // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: {{.*}} in function declaration + // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: {{.*}} in function declaration + // CHECK-FIXES: {{^}} void (*(*returns_fn_returns_fn_void_void())())();{{$}} + + void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)(void))(void))(void); + // CHECK-MESSAGES: :[[@LINE-1]]:58: warning: {{.*}} in field declaration + // CHECK-MESSAGES: :[[@LINE-2]]:65: warning: {{.*}} in field declaration + // CHECK-MESSAGES: :[[@LINE-3]]:72: warning: {{.*}} in field declaration + // CHECK-FIXES: {{^}} void (*(*(gronk::*returns_fn_returns_fn_void_void_mem)())())();{{$}} +}; + +int i; +int *pi; +void *pv = (void *) pi; +float f; +float *fi; +double d; +double *pd; + +void (*f1)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration +// CHECK-FIXES: {{^}}void (*f1)();{{$}} + +void (*f2)(void) = nullptr; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2)() = nullptr;{{$}} + +void (*f2b)(void)(nullptr); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2b)()(nullptr);{{$}} + +void (*f2c)(void){nullptr}; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2c)(){nullptr};{{$}} + +void (*f2d)(void) = NULL; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2d)() = NULL;{{$}} + +void (*f2e)(void)(NULL); +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2e)()(NULL);{{$}} + +void (*f2f)(void){NULL}; +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f2f)(){NULL};{{$}} + +void (*f3)(void) = bar; +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (*f3)() = bar;{{$}} + +void (*o1)(int i); +void (*o2)(int i) = nullptr; +void (*o3)(int i)(nullptr); +void (*o4)(int i){nullptr}; +void (*o5)(int i) = NULL; +void (*o6)(int i)(NULL); +void (*o7)(int i){NULL}; +void (*o8)(int i) = op_fn; + +void (*fa)(); + +void (*fb)() = nullptr; + +void (*fc)() = bar; + +typedef void (function_ptr)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:29: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef void (function_ptr)();{{$}} + +// intentionally not LLVM style to check preservation of whitesapce +typedef void (function_ptr2) + ( + void + ); +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef +// CHECK-FIXES: {{^typedef void \(function_ptr2\)$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ $}} +// CHECK-FIXES-NEXT: {{^ \);$}} + +// intentionally not LLVM style to check preservation of whitesapce +typedef +void +( +* +( +* +returns_fn_returns_fn_void_void_t2 +( +void +) +) +( +void +) +) +( +void +) +; +// CHECK-MESSAGES: :[[@LINE-11]]:1: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-8]]:1: warning: {{.*}} in typedef +// CHECK-MESSAGES: :[[@LINE-5]]:1: warning: {{.*}} in typedef +// CHECK-FIXES: {{^typedef$}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^\*$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^\*$}} +// CHECK-FIXES-NEXT: {{^returns_fn_returns_fn_void_void_t2$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NOT: {{[^ ]}} +// CHECK-FIXES: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NOT: {{[^ ]}} +// CHECK-FIXES: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NOT: {{[^ ]}} +// CHECK-FIXES: {{^\)$}} +// CHECK-FIXES-NEXT: {{^;$}} + + +void (gronk::*p1)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration +// CHECK-FIXES: {{^}}void (gronk::*p1)();{{$}} + +void (gronk::*p2)(void) = &gronk::foo; +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration with initializer +// CHECK-FIXES: {{^}}void (gronk::*p2)() = &gronk::foo;{{$}} + +typedef void (gronk::*member_function_ptr)(void); +// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: {{.*}} in typedef +// CHECK-FIXES: {{^}}typedef void (gronk::*member_function_ptr)();{{$}} + +// intentionally not LLVM style to check preservation of whitesapce +typedef void (gronk::*member_function_ptr2) + ( + void + ); +// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: {{.*}} in typedef +// CHECK-FIXES: {{^typedef void \(gronk::\*member_function_ptr2\)$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ $}} +// CHECK-FIXES-NEXT: {{^ \);$}} + +void gronk::foo() { + void (*f1)(void) = &::bar; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-FIXES: {{^ }}void (*f1)() = &::bar;{{$}} + + void (*f2)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (*f2)();{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f3) + ( + void + ); + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (*f3){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NEXT: {{^ $}} + // CHECK-FIXES-NEXT: {{^ \);$}} +} + +void gronk::bar(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}void gronk::bar() {{{$}} + void (gronk::*p3)(void) = &gronk::foo; + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration with initializer + // CHECK-FIXES: {{^ }}void (gronk::*p3)() = &gronk::foo;{{$}} + + void (gronk::*p4)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (gronk::*p4)();{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (gronk::*p5) + ( + void + ); + // CHECK-MESSAGES: :[[@LINE-2]]:11: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (gronk::*p5){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NExT: {{^ $}} + // CHECK-FIXES-NExT: {{^ \);$}} +} + +// intentionally not LLVM style to check preservation of whitesapce +void gronk::bar2 + ( + void + ) +// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: {{.*}} in function definition +// CHECK-FIXES: {{^void gronk::bar2$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ $}} +// CHECK-FIXES-NEXT: {{^ \)$}} +{ +} + +gronk::gronk(void) +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}gronk::gronk(){{$}} + : f1(nullptr), + p1(nullptr) { +} + +gronk::~gronk(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}gronk::~gronk() {{{$}} +} + +class nutter { +public: + nutter(); +}; + +nutter::nutter(void) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in function definition +// CHECK-FIXES: {{^}}nutter::nutter() {{{$}} + void (*f3)(void) = static_cast(0); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:43: warning: {{.*}} in named cast + // CHECK-FIXES: void (*f3)() = static_cast(0);{{$}} + + void (*f4)(void) = (void (*)(void)) 0; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: {{.*}} in cast expression + // CHECK-FIXES: void (*f4)() = (void (*)()) 0;{{$}} + + void (*f5)(void) = reinterpret_cast(0); + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:48: warning: {{.*}} in named cast + // CHECK-FIXES: void (*f5)() = reinterpret_cast(0);{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f6)(void) = static_cast(0); + // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast + // CHECK-FIXES: {{^ }}void (*f6)() = static_cast(0);{{$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f7)(void) = (void (*) + ( + void + )) 0; + // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in cast expression + // CHECK-FIXES: {{^ }}void (*f7)() = (void (*){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NEXT: {{^ $}} + // CHECK-FIXES-NEXT: {{^ \)\) 0;$}} + + // intentionally not LLVM style to check preservation of whitesapce + void (*f8)(void) = reinterpret_cast(0); + // CHECK-MESSAGES: :[[@LINE-4]]:14: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:11: warning: {{.*}} in named cast + // CHECK-FIXES: {{^ }}void (*f8)() = reinterpret_cast\(0\);$}} + + void (*o1)(int) = static_cast(0); + void (*o2)(int) = (void (*)(int)) 0; + void (*o3)(int) = reinterpret_cast(0); +} + +class generator { +public: + int operator()(void) { return 1; } + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: {{.*}} in function definition + // CHECK-FIXES: {{^ }}int operator()() { return 1; }{{$}} +}; + +void test_lambda_functions() { + auto lamb_duh = [](void (*fn)(void)) { (*fn)(); }; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}auto lamb_duh = [](void (*fn)()) { (*fn)(); };{{$}} + + auto lambda_generator = [](void) { return 1; }; + // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: {{.*}} in lambda expression + // CHECK-FIXES: {{^ }}auto lambda_generator = []() { return 1; };{{$}} + + auto gen2 = []() { return 1; }; + + auto gen3 = []{ return 1; }; + + auto void_returner = [](void) -> void (*)(void) { return f1; }; + // CHECK-MESSAGES: [[@LINE-1]]:27: warning: {{.*}} in lambda expression + // CHECK-MESSAGES: [[@LINE-2]]:45: warning: {{.*}} in lambda expression + // CHECK-FIXES: {{^ }}auto void_returner = []() -> void (*)() { return f1; };{{$}} +}