Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -8,6 +8,7 @@ NamespaceCommentCheck.cpp ReadabilityTidyModule.cpp RedundantSmartptrGet.cpp + RedundantVoidArg.cpp ShrinkToFitCheck.cpp LINK_LIBS Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -15,6 +15,7 @@ #include "ElseAfterReturnCheck.h" #include "FunctionSize.h" #include "RedundantSmartptrGet.h" +#include "RedundantVoidArg.h" #include "ShrinkToFitCheck.h" namespace clang { @@ -34,8 +35,9 @@ "readability-function-size"); CheckFactories.registerCheck( "readability-redundant-smartptr-get"); - CheckFactories.registerCheck( - "readability-shrink-to-fit"); + CheckFactories.registerCheck( + "readability-redundant-void-arg"); + CheckFactories.registerCheck("readability-shrink-to-fit"); } }; @@ -43,7 +45,7 @@ // Register the MiscTidyModule using this statically initialized variable. static ClangTidyModuleRegistry::Add -X("readability-module", "Adds readability-related checks."); + X("readability-module", "Adds readability-related checks."); // This anchor is used to force the linker to link in the generated object file // and thus register the MiscModule. Index: clang-tidy/readability/RedundantVoidArg.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantVoidArg.h @@ -0,0 +1,79 @@ +//===--- RedundantVoidArg.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_READABILITY_REDUNDANT_VOID_ARG_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_VOID_ARG_H + +#include "../ClangTidy.h" +#include "clang/Lex/Token.h" + +#include + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief Find and remove redundant void argument lists. +/// +/// Examples: +/// int foo(void); ==> int foo(); +class RedundantVoidArg : public ClangTidyCheck { +public: + RedundantVoidArg(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 + processCStyleCastExpr(const ast_matchers::MatchFinder::MatchResult &Result, + const CStyleCastExpr *CStyleCast); + + void + processFunctionalCast(const ast_matchers::MatchFinder::MatchResult &Result, + const CXXFunctionalCastExpr *FunctionalCast); + + 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, + SourceLocation StartLoc, const std::string &DeclText, + StringRef GrammarLocation); + + void removeVoidToken(Token VoidToken, const StringRef Diagnostic); +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_VOID_ARG_H Index: clang-tidy/readability/RedundantVoidArg.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantVoidArg.cpp @@ -0,0 +1,307 @@ +//===- RedundantVoidArg.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 "RedundantVoidArg.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Lexer.h" + +using namespace clang; +using namespace clang::ast_matchers; + +namespace { + +// Returns the source text for a source range +StringRef getText(const MatchFinder::MatchResult &Result, SourceRange Range) { + return Lexer::getSourceText(CharSourceRange::getTokenRange(Range), + *Result.SourceManager, + Result.Context->getLangOpts()); +} + +// Returns the source text for a pair of source locations. +StringRef getText(const MatchFinder::MatchResult &Result, SourceLocation Begin, + SourceLocation End) { + return getText(Result, SourceRange(Begin, End)); +} + +// Returns the text that makes up 'node' in the source. +// Returns an empty string if the text cannot be found. +template +StringRef getText(const MatchFinder::MatchResult &Result, const T &Node) { + return getText(Result, Node.getSourceRange()); +} + +// Determine if the given QualType is a nullary function or pointer to same. +bool protoTypeHasNoParms(QualType QT) { + if (const auto PT = QT->getAs()) { + QT = PT->getPointeeType(); + } + if (const auto *MPT = QT->getAs()) { + QT = MPT->getPointeeType(); + } + if (const 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 FunctionalCastId[] = "fn-cast"; +const char LambdaId[] = "lambda"; + +} // namespace + +namespace clang { +namespace tidy { +namespace readability { + +void RedundantVoidArg::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( + staticCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(NamedCastId), + this); + Finder->addMatcher( + reinterpretCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(NamedCastId), + this); + Finder->addMatcher(constCastExpr(isExpansionInMainFile(), + CastDestinationIsFunction).bind(NamedCastId), + this); + Finder->addMatcher( + functionalCastExpr(isExpansionInMainFile(), CastDestinationIsFunction) + .bind(FunctionalCastId), + this); + Finder->addMatcher(lambdaExpr(isExpansionInMainFile()).bind(LambdaId), this); +} + +void RedundantVoidArg::check(const MatchFinder::MatchResult &Result) { + if (!Result.Context->getLangOpts().CPlusPlus) { + return; + } + + auto &Nodes = Result.Nodes; + if (auto Function = Nodes.getNodeAs(FunctionId)) { + processFunctionDecl(Result, Function); + } else if (auto Typedef = Nodes.getNodeAs(TypedefId)) { + processTypedefDecl(Result, Typedef); + } else if (auto Member = Nodes.getNodeAs(FieldId)) { + processFieldDecl(Result, Member); + } else if (auto Var = Nodes.getNodeAs(VarId)) { + processVarDecl(Result, Var); + } else if (auto NamedCast = Nodes.getNodeAs(NamedCastId)) { + processNamedCastExpr(Result, NamedCast); + } else if (auto CStyleCast = Nodes.getNodeAs(CStyleCastId)) { + processCStyleCastExpr(Result, CStyleCast); + } else if (auto FunctionalCast = + Nodes.getNodeAs(FunctionalCastId)) { + processFunctionalCast(Result, FunctionalCast); + } else if (auto ExplicitCast = + Nodes.getNodeAs(ExplicitCastId)) { + processExplicitCastExpr(Result, ExplicitCast); + } else if (auto Lambda = Nodes.getNodeAs(LambdaId)) { + processLambdaExpr(Result, Lambda); + } +} + +void +RedundantVoidArg::processFunctionDecl(const MatchFinder::MatchResult &Result, + const FunctionDecl *const Function) { + SourceLocation Start = Function->getLocStart(); + if (Function->isThisDeclarationADefinition()) { + SourceLocation BeforeBody = + Function->getBody()->getLocStart().getLocWithOffset(-1); + std::string DeclText = getText(Result, Start, BeforeBody); + removeVoidArgumentTokens(Result, Start, DeclText, "function definition"); + } else { + std::string Text = getText(Result, *Function); + removeVoidArgumentTokens(Result, Start, Text, "function declaration"); + } +} + +void RedundantVoidArg::removeVoidArgumentTokens( + const MatchFinder::MatchResult &Result, SourceLocation StartLoc, + const std::string &DeclText, StringRef GrammarLocation) { + clang::Lexer PrototypeLexer(StartLoc, 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 RedundantVoidArg::removeVoidToken(Token VoidToken, + const StringRef Diagnostic) { + SourceLocation VoidLoc(VoidToken.getLocation()); + const auto VoidRange = SourceRange(VoidLoc, VoidLoc.getLocWithOffset(3)); + diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange); +} + +void +RedundantVoidArg::processTypedefDecl(const MatchFinder::MatchResult &Result, + const TypedefDecl *const Typedef) { + if (protoTypeHasNoParms(Typedef->getUnderlyingType())) { + StringRef Text = getText(Result, *Typedef); + removeVoidArgumentTokens(Result, Typedef->getLocStart(), Text.str(), + "typedef"); + } +} + +void RedundantVoidArg::processFieldDecl(const MatchFinder::MatchResult &Result, + const FieldDecl *const Member) { + if (protoTypeHasNoParms(Member->getType())) { + StringRef Text = getText(Result, *Member); + removeVoidArgumentTokens(Result, Member->getLocStart(), Text.str(), + "field declaration"); + } +} + +void RedundantVoidArg::processVarDecl(const MatchFinder::MatchResult &Result, + const VarDecl *const Var) { + if (protoTypeHasNoParms(Var->getType())) { + SourceLocation Begin = Var->getLocStart(); + if (Var->hasInit()) { + SourceLocation InitStart = + Result.SourceManager->getExpansionLoc(Var->getInit()->getLocStart()) + .getLocWithOffset(-1); + StringRef Text = getText(Result, Begin, InitStart); + removeVoidArgumentTokens(Result, Begin, Text.str(), + "variable declaration with initializer"); + } else { + StringRef Text = getText(Result, *Var); + removeVoidArgumentTokens(Result, Begin, Text.str(), + "variable declaration"); + } + } +} + +void RedundantVoidArg::processNamedCastExpr( + const MatchFinder::MatchResult &Result, + const CXXNamedCastExpr *const NamedCast) { + if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) { + SourceRange AngleBrackets = NamedCast->getAngleBrackets(); + SourceLocation Begin = AngleBrackets.getBegin().getLocWithOffset(1); + SourceLocation End = AngleBrackets.getEnd().getLocWithOffset(-1); + StringRef TemplateArgument = getText(Result, Begin, End); + removeVoidArgumentTokens(Result, Begin, TemplateArgument.str(), + "named cast"); + } +} + +void RedundantVoidArg::processCStyleCastExpr( + const MatchFinder::MatchResult &Result, + const CStyleCastExpr *const CStyleCast) { + if (protoTypeHasNoParms(CStyleCast->getTypeAsWritten())) { + SourceLocation Begin = CStyleCast->getLParenLoc().getLocWithOffset(1); + SourceLocation End = CStyleCast->getRParenLoc().getLocWithOffset(-1); + StringRef ExprText = getText(Result, Begin, End); + removeVoidArgumentTokens(Result, Begin, ExprText.str(), "C style cast"); + } +} + +void RedundantVoidArg::processFunctionalCast( + const MatchFinder::MatchResult &Result, + const CXXFunctionalCastExpr *const FunctionalCast) { + if (protoTypeHasNoParms(FunctionalCast->getTypeAsWritten())) { + SourceLocation Begin = FunctionalCast->getLocStart(); + StringRef ExprText = getText( + Result, Begin, FunctionalCast->getLParenLoc().getLocWithOffset(-1)); + removeVoidArgumentTokens(Result, Begin, ExprText.str(), "functional cast"); + } +} + +void RedundantVoidArg::processExplicitCastExpr( + const MatchFinder::MatchResult &Result, + const ExplicitCastExpr *const ExplicitCast) { + if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten())) { + StringRef ExprText = getText(Result, *ExplicitCast); + removeVoidArgumentTokens(Result, ExplicitCast->getLocStart(), + ExprText.str(), "explicit cast"); + } +} + +void RedundantVoidArg::processLambdaExpr(const MatchFinder::MatchResult &Result, + const LambdaExpr *const Lambda) { + if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 && + Lambda->hasExplicitParameters()) { + SourceLocation Begin = + Lambda->getIntroducerRange().getEnd().getLocWithOffset(1); + SourceLocation End = Lambda->getBody()->getLocStart().getLocWithOffset(-1); + StringRef LambdaProtoText = getText(Result, Begin, End); + removeVoidArgumentTokens(Result, Begin, LambdaProtoText.str(), + "lambda expression"); + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: test/clang-tidy/readability-redundant-void-arg.c =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-void-arg.c @@ -0,0 +1,128 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-remove-void-arg %t -- -x c +// REQUIRES: shell + +#include + +extern int i; + +int foo2() +{ + return 0; +} + +int j = 1; + +int foo(void) +// CHECK-FIXES: {{^}}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); +// CHECK-FIXES: {{^}}int (*returns_fn_void_int(void))(void);{{$}} + +typedef int (*returns_fn_void_int_t(void))(void); +// CHECK-FIXES: {{^}}typedef int (*returns_fn_void_int_t(void))(void);{{$}} + +int (*returns_fn_void_int(void))(void) +// CHECK-FIXES: {{^}}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); +// CHECK-FIXES: {{^}}void (*(*returns_fn_returns_fn_void_void(void))(void))(void);{{$}} + +typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void); +// CHECK-FIXES: {{^}}typedef void (*(*returns_fn_returns_fn_void_void_t(void))(void))(void);{{$}} + +void (*(*returns_fn_returns_fn_void_void(void))(void))(void) +// CHECK-FIXES: {{^}}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); +// CHECK-FIXES: {{^}}void (*f1)(void);{{$}} + +void (*f2)(void) = NULL; +// CHECK-FIXES: {{^}}void (*f2)(void) = NULL;{{$}} + +void (*f3)(void) = bar; +// CHECK-FIXES: {{^}}void (*f3)(void) = bar;{{$}} + +void (*fa)(); + +void (*fb)() = NULL; + +void (*fc)() = bar; + +typedef void (function_ptr)(void); +// CHECK-FIXES: {{^}}typedef void (function_ptr)(void);{{$}} + +typedef void (function_ptr2) + ( + void + ); +// CHECK-FIXES: {{^}}typedef void (function_ptr2){{$}} +// CHECK-FIXES-NEXT: {{^ \($}} +// CHECK-FIXES-NEXT: {{^ void$}} +// CHECK-FIXES-NEXT: {{^ \);$}} + +typedef +void +( +* +( +* +returns_fn_returns_fn_void_void_t2 +( +void +) +) +( +void +) +) +( +void +) +; +// 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-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^\($}} +// CHECK-FIXES-NEXT: {{^void$}} +// CHECK-FIXES-NEXT: {{^\)$}} +// CHECK-FIXES-NEXT: {{^;$}} Index: test/clang-tidy/readability-redundant-void-arg.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-void-arg.cpp @@ -0,0 +1,426 @@ +// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-redundant-void-arg %t +// REQUIRES: shell + +#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 [readability-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]]:23: 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]]:46: warning: {{.*}} in function declaration + // CHECK-MESSAGES: :[[@LINE-2]]:53: warning: {{.*}} in function declaration + // CHECK-MESSAGES: :[[@LINE-3]]:60: 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]]:60: warning: {{.*}} in field declaration + // CHECK-MESSAGES: :[[@LINE-2]]:67: warning: {{.*}} in field declaration + // CHECK-MESSAGES: :[[@LINE-3]]:74: 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)();{{$}} + +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: {{^ \);$}} + +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)();{{$}} + +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]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-FIXES: {{^ }}void (*f1)() = &::bar;{{$}} + + void (*f2)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (*f2)();{{$}} + + void (*f3) + ( + void + ); + // CHECK-MESSAGES: :[[@LINE-2]]:13: 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]]:23: warning: {{.*}} in variable declaration with initializer + // CHECK-FIXES: {{^ }}void (gronk::*p3)() = &gronk::foo;{{$}} + + void (gronk::*p4)(void); + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (gronk::*p4)();{{$}} + + void (gronk::*p5) + ( + void + ); + // CHECK-MESSAGES: :[[@LINE-2]]:13: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}void (gronk::*p5){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NExT: {{^ $}} + // CHECK-FIXES-NExT: {{^ \);$}} +} + +void gronk::bar2 + ( + void + ) +// CHECK-MESSAGES: :[[@LINE-2]]:5: 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]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:45: warning: {{.*}} in named cast + // CHECK-FIXES: void (*f3)() = static_cast(0);{{$}} + + void (*f4)(void) = (void (*)(void)) 0; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: {{.*}} in C style cast + // CHECK-FIXES: void (*f4)() = (void (*)()) 0;{{$}} + + void (*f5)(void) = reinterpret_cast(0); + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-2]]:50: warning: {{.*}} in named cast + // CHECK-FIXES: void (*f5)() = reinterpret_cast(0);{{$}} + + void (*f6)(void) = static_cast(0); + // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: {{.*}} in named cast + // CHECK-FIXES: {{^ }}void (*f6)() = static_cast(0);{{$}} + + void (*f7)(void) = (void (*) + ( + void + )) 0; + // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:13: warning: {{.*}} in C style cast + // CHECK-FIXES: {{^ }}void (*f7)() = (void (*){{$}} + // CHECK-FIXES-NEXT: {{^ \($}} + // CHECK-FIXES-NEXT: {{^ $}} + // CHECK-FIXES-NEXT: {{^ \)\) 0;$}} + + void (*f8)(void) = reinterpret_cast(0); + // CHECK-MESSAGES: :[[@LINE-4]]:16: warning: {{.*}} in variable declaration with initializer + // CHECK-MESSAGES: :[[@LINE-3]]:13: 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]]:20: 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]]:35: warning: {{.*}} in variable declaration + // CHECK-FIXES: {{^ }}auto lamb_duh = [](void (*fn)()) { (*fn)(); };{{$}} + + auto lambda_generator = [](void) { return 1; }; + // CHECK-MESSAGES: :[[@LINE-1]]:32: 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]]:29: warning: {{.*}} in lambda expression + // CHECK-MESSAGES: [[@LINE-2]]:47: warning: {{.*}} in lambda expression + // CHECK-FIXES: {{^ }}auto void_returner = []() -> void (*)() { return f1; };{{$}} +}