Index: clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp =================================================================== --- clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp +++ clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp @@ -48,7 +48,7 @@ unless(isInstantiated()), unless(isExternC())) .bind(FunctionId), this); - Finder->addMatcher(typedefNameDecl().bind(TypedefId), this); + Finder->addMatcher(typedefNameDecl(unless(isImplicit())).bind(TypedefId), this); auto ParenFunctionType = parenType(innerType(functionType())); auto PointerToFunctionType = pointee(ParenFunctionType); auto FunctionOrMemberPointer = @@ -97,9 +97,12 @@ void RedundantVoidArgCheck::processFunctionDecl( const MatchFinder::MatchResult &Result, const FunctionDecl *Function) { + const auto *Method = dyn_cast(Function); + SourceLocation Start = Method && Method->getParent()->isLambda() + ? Method->getBeginLoc() + : Function->getLocation(); + SourceLocation End = Function->getEndLoc(); if (Function->isThisDeclarationADefinition()) { - SourceLocation Start = Function->getBeginLoc(); - SourceLocation End = Function->getEndLoc(); if (const Stmt *Body = Function->getBody()) { End = Body->getBeginLoc(); if (End.isMacroID() && @@ -110,11 +113,16 @@ removeVoidArgumentTokens(Result, SourceRange(Start, End), "function definition"); } else { - removeVoidArgumentTokens(Result, Function->getSourceRange(), + removeVoidArgumentTokens(Result, SourceRange(Start, End), "function declaration"); } } +bool isMacroIdentifier(IdentifierTable &Idents, const Token &ProtoToken) { + return ProtoToken.is(tok::TokenKind::raw_identifier) && + Idents.get(ProtoToken.getRawIdentifier()).hadMacroDefinition(); +} + void RedundantVoidArgCheck::removeVoidArgumentTokens( const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range, StringRef GrammarLocation) { @@ -127,47 +135,93 @@ .str(); Lexer PrototypeLexer(CharRange.getBegin(), getLangOpts(), DeclText.data(), DeclText.data(), DeclText.data() + DeclText.size()); - enum TokenState { - NothingYet, - SawLeftParen, - SawVoid, + enum class TokenState { + Start, + MacroId, + MacroLeftParen, + MacroArguments, + LeftParen, + Void, }; - TokenState State = NothingYet; + TokenState State = TokenState::Start; Token VoidToken; Token ProtoToken; + IdentifierTable &Idents = Result.Context->Idents; + int MacroLevel = 0; std::string Diagnostic = ("redundant void argument list in " + GrammarLocation).str(); while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) { switch (State) { - case NothingYet: + case TokenState::Start: + if (ProtoToken.is(tok::TokenKind::l_paren)) { + State = TokenState::LeftParen; + } else if (isMacroIdentifier(Idents, ProtoToken)) { + State = TokenState::MacroId; + } + break; + case TokenState::MacroId: if (ProtoToken.is(tok::TokenKind::l_paren)) { - State = SawLeftParen; + State = TokenState::MacroLeftParen; + } else { + State = TokenState::Start; + } + break; + case TokenState::MacroLeftParen: + ++MacroLevel; + if (ProtoToken.is(tok::TokenKind::raw_identifier)) { + if (isMacroIdentifier(Idents, ProtoToken)) { + State = TokenState::MacroId; + } else { + State = TokenState::MacroArguments; + } + } else if (ProtoToken.is(tok::TokenKind::r_paren)) { + --MacroLevel; + if (MacroLevel == 0) { + State = TokenState::Start; + } else { + State = TokenState::MacroId; + } + } else { + State = TokenState::MacroArguments; + } + break; + case TokenState::MacroArguments: + if (isMacroIdentifier(Idents, ProtoToken)) { + State = TokenState::MacroLeftParen; + } else if (ProtoToken.is(tok::TokenKind::r_paren)) { + --MacroLevel; + if (MacroLevel == 0) { + State = TokenState::Start; + } } break; - case SawLeftParen: - if (ProtoToken.is(tok::TokenKind::raw_identifier) && - ProtoToken.getRawIdentifier() == "void") { - State = SawVoid; - VoidToken = ProtoToken; + case TokenState::LeftParen: + if (ProtoToken.is(tok::TokenKind::raw_identifier)) { + if (isMacroIdentifier(Idents, ProtoToken)) { + State = TokenState::MacroId; + } else if (ProtoToken.getRawIdentifier() == "void") { + State = TokenState::Void; + VoidToken = ProtoToken; + } } else if (ProtoToken.is(tok::TokenKind::l_paren)) { - State = SawLeftParen; + State = TokenState::LeftParen; } else { - State = NothingYet; + State = TokenState::Start; } break; - case SawVoid: - State = NothingYet; + case TokenState::Void: + State = TokenState::Start; if (ProtoToken.is(tok::TokenKind::r_paren)) { removeVoidToken(VoidToken, Diagnostic); } else if (ProtoToken.is(tok::TokenKind::l_paren)) { - State = SawLeftParen; + State = TokenState::LeftParen; } break; } } - if (State == SawVoid && ProtoToken.is(tok::TokenKind::r_paren)) { + if (State == TokenState::Void && ProtoToken.is(tok::TokenKind::r_paren)) { removeVoidToken(VoidToken, Diagnostic); } } Index: clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp +++ clang-tools-extra/test/clang-tidy/checkers/modernize-redundant-void-arg.cpp @@ -199,6 +199,7 @@ // CHECK-FIXES-NEXT: {{^ \);$}} // intentionally not LLVM style to check preservation of whitespace +// clang-format off typedef void ( @@ -240,7 +241,7 @@ // CHECK-FIXES-NOT: {{[^ ]}} // CHECK-FIXES: {{^\)$}} // CHECK-FIXES-NEXT: {{^;$}} - +// clang-format on void (gronk::*p1)(void); // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: {{.*}} in variable declaration @@ -556,3 +557,38 @@ S_3(); g_3(); } + +#define return_t(T) T +extern return_t(void) func(void); +// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: redundant void argument list in function declaration +// CHECK-FIXES: extern return_t(void) func(); + +return_t(void) func(void) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: redundant void argument list in function definition + // CHECK-FIXES: return_t(void) func() { + int a; + (void)a; +} + +extern return_t(void) func(return_t(void) (*fp)(void)); +// CHECK-MESSAGES: :[[@LINE-1]]:49: warning: redundant void argument list in variable declaration +// CHECK-FIXES: extern return_t(void) func(return_t(void) (*fp)()); + +return_t(void) func(return_t(void) (*fp)(void)) { + // CHECK-MESSAGES: :[[@LINE-1]]:42: warning: redundant void argument list in variable declaration + // CHECK-FIXES: return_t(void) func(return_t(void) (*fp)()) { + int a; + (void)a; +} + +extern return_t(return_t(void)) func2(return_t(return_t(void)) (*fp)(void)); +// CHECK-MESSAGES: :[[@LINE-1]]:70: warning: redundant void argument list in variable declaration +// CHECK-FIXES: extern return_t(return_t(void)) func2(return_t(return_t(void)) (*fp)()); + +return_t(return_t(void)) func2(return_t(return_t(void)) (*fp)(void)) { + // CHECK-MESSAGES: :[[@LINE-1]]:63: warning: redundant void argument list in variable declaration + // CHECK-FIXES: return_t(return_t(void)) func2(return_t(return_t(void)) (*fp)()) { + int a; + (void)a; +} +#undef return_t