Skip to content

Commit 52be8ca

Browse files
committed
[clang-tidy] Refactor modernize-redundant-void-arg
1 parent b1d0e5f commit 52be8ca

File tree

4 files changed

+136
-396
lines changed

4 files changed

+136
-396
lines changed

clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp

Lines changed: 33 additions & 264 deletions
Original file line numberDiff line numberDiff line change
@@ -7,281 +7,50 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "RedundantVoidArgCheck.h"
10-
#include "clang/Frontend/CompilerInstance.h"
11-
#include "clang/Lex/Lexer.h"
10+
#include "../utils/LexerUtils.h"
11+
#include "clang/ASTMatchers/ASTMatchers.h"
1212

1313
using namespace clang::ast_matchers;
14+
using namespace clang::ast_matchers::internal;
1415

1516
namespace clang::tidy::modernize {
1617

17-
// Determine if the given QualType is a nullary function or pointer to same.
18-
static bool protoTypeHasNoParms(QualType QT) {
19-
if (const auto *PT = QT->getAs<PointerType>())
20-
QT = PT->getPointeeType();
21-
if (auto *MPT = QT->getAs<MemberPointerType>())
22-
QT = MPT->getPointeeType();
23-
if (const auto *FP = QT->getAs<FunctionProtoType>())
24-
return FP->getNumParams() == 0;
25-
return false;
26-
}
27-
28-
static const char FunctionId[] = "function";
29-
static const char TypedefId[] = "typedef";
30-
static const char FieldId[] = "field";
31-
static const char VarId[] = "var";
32-
static const char NamedCastId[] = "named-cast";
33-
static const char CStyleCastId[] = "c-style-cast";
34-
static const char ExplicitCastId[] = "explicit-cast";
35-
static const char LambdaId[] = "lambda";
36-
3718
void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) {
38-
Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()),
39-
unless(isInstantiated()), unless(isExternC()))
40-
.bind(FunctionId),
41-
this);
42-
Finder->addMatcher(typedefNameDecl(unless(isImplicit())).bind(TypedefId),
19+
const VariadicDynCastAllOfMatcher<TypeLoc, FunctionProtoTypeLoc>
20+
functionProtoTypeLoc; // NOLINT(readability-identifier-naming)
21+
Finder->addMatcher(traverse(TK_IgnoreUnlessSpelledInSource,
22+
functionProtoTypeLoc(
23+
unless(hasParent(functionDecl(isExternC()))))
24+
.bind("fn")),
4325
this);
44-
auto ParenFunctionType = parenType(innerType(functionType()));
45-
auto PointerToFunctionType = pointee(ParenFunctionType);
46-
auto FunctionOrMemberPointer =
47-
anyOf(hasType(pointerType(PointerToFunctionType)),
48-
hasType(memberPointerType(PointerToFunctionType)));
49-
Finder->addMatcher(fieldDecl(FunctionOrMemberPointer).bind(FieldId), this);
50-
Finder->addMatcher(varDecl(FunctionOrMemberPointer).bind(VarId), this);
51-
auto CastDestinationIsFunction =
52-
hasDestinationType(pointsTo(ParenFunctionType));
5326
Finder->addMatcher(
54-
cStyleCastExpr(CastDestinationIsFunction).bind(CStyleCastId), this);
55-
Finder->addMatcher(
56-
cxxStaticCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
57-
Finder->addMatcher(
58-
cxxReinterpretCastExpr(CastDestinationIsFunction).bind(NamedCastId),
59-
this);
60-
Finder->addMatcher(
61-
cxxConstCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
62-
Finder->addMatcher(lambdaExpr().bind(LambdaId), this);
27+
traverse(TK_IgnoreUnlessSpelledInSource, lambdaExpr().bind("fn")), this);
6328
}
6429

6530
void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) {
66-
const BoundNodes &Nodes = Result.Nodes;
67-
if (const auto *Function = Nodes.getNodeAs<FunctionDecl>(FunctionId))
68-
processFunctionDecl(Result, Function);
69-
else if (const auto *TypedefName =
70-
Nodes.getNodeAs<TypedefNameDecl>(TypedefId))
71-
processTypedefNameDecl(Result, TypedefName);
72-
else if (const auto *Member = Nodes.getNodeAs<FieldDecl>(FieldId))
73-
processFieldDecl(Result, Member);
74-
else if (const auto *Var = Nodes.getNodeAs<VarDecl>(VarId))
75-
processVarDecl(Result, Var);
76-
else if (const auto *NamedCast =
77-
Nodes.getNodeAs<CXXNamedCastExpr>(NamedCastId))
78-
processNamedCastExpr(Result, NamedCast);
79-
else if (const auto *CStyleCast =
80-
Nodes.getNodeAs<CStyleCastExpr>(CStyleCastId))
81-
processExplicitCastExpr(Result, CStyleCast);
82-
else if (const auto *ExplicitCast =
83-
Nodes.getNodeAs<ExplicitCastExpr>(ExplicitCastId))
84-
processExplicitCastExpr(Result, ExplicitCast);
85-
else if (const auto *Lambda = Nodes.getNodeAs<LambdaExpr>(LambdaId))
86-
processLambdaExpr(Result, Lambda);
87-
}
88-
89-
void RedundantVoidArgCheck::processFunctionDecl(
90-
const MatchFinder::MatchResult &Result, const FunctionDecl *Function) {
91-
const auto *Method = dyn_cast<CXXMethodDecl>(Function);
92-
const SourceLocation Start = Method && Method->getParent()->isLambda()
93-
? Method->getBeginLoc()
94-
: Function->getLocation();
95-
SourceLocation End = Function->getEndLoc();
96-
if (Function->isThisDeclarationADefinition()) {
97-
if (const Stmt *Body = Function->getBody()) {
98-
End = Body->getBeginLoc();
99-
if (End.isMacroID() &&
100-
Result.SourceManager->isAtStartOfImmediateMacroExpansion(End))
101-
End = Result.SourceManager->getExpansionLoc(End);
102-
End = End.getLocWithOffset(-1);
103-
}
104-
removeVoidArgumentTokens(Result, SourceRange(Start, End),
105-
"function definition");
106-
} else
107-
removeVoidArgumentTokens(Result, SourceRange(Start, End),
108-
"function declaration");
109-
}
110-
111-
static bool isMacroIdentifier(const IdentifierTable &Idents,
112-
const Token &ProtoToken) {
113-
if (!ProtoToken.is(tok::TokenKind::raw_identifier))
114-
return false;
115-
116-
const IdentifierTable::iterator It =
117-
Idents.find(ProtoToken.getRawIdentifier());
118-
if (It == Idents.end())
119-
return false;
120-
121-
return It->second->hadMacroDefinition();
122-
}
123-
124-
void RedundantVoidArgCheck::removeVoidArgumentTokens(
125-
const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range,
126-
StringRef GrammarLocation) {
127-
const CharSourceRange CharRange =
128-
Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Range),
129-
*Result.SourceManager, getLangOpts());
130-
131-
std::string DeclText =
132-
Lexer::getSourceText(CharRange, *Result.SourceManager, getLangOpts())
133-
.str();
134-
Lexer PrototypeLexer(CharRange.getBegin(), getLangOpts(), DeclText.data(),
135-
DeclText.data(), DeclText.data() + DeclText.size());
136-
enum class TokenState {
137-
Start,
138-
MacroId,
139-
MacroLeftParen,
140-
MacroArguments,
141-
LeftParen,
142-
Void,
143-
};
144-
TokenState State = TokenState::Start;
145-
Token VoidToken;
146-
Token ProtoToken;
147-
const IdentifierTable &Idents = Result.Context->Idents;
148-
int MacroLevel = 0;
149-
const std::string Diagnostic =
150-
("redundant void argument list in " + GrammarLocation).str();
151-
152-
while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) {
153-
switch (State) {
154-
case TokenState::Start:
155-
if (ProtoToken.is(tok::TokenKind::l_paren))
156-
State = TokenState::LeftParen;
157-
else if (isMacroIdentifier(Idents, ProtoToken))
158-
State = TokenState::MacroId;
159-
break;
160-
case TokenState::MacroId:
161-
if (ProtoToken.is(tok::TokenKind::l_paren))
162-
State = TokenState::MacroLeftParen;
163-
else
164-
State = TokenState::Start;
165-
break;
166-
case TokenState::MacroLeftParen:
167-
++MacroLevel;
168-
if (ProtoToken.is(tok::TokenKind::raw_identifier)) {
169-
if (isMacroIdentifier(Idents, ProtoToken))
170-
State = TokenState::MacroId;
171-
else
172-
State = TokenState::MacroArguments;
173-
} else if (ProtoToken.is(tok::TokenKind::r_paren)) {
174-
--MacroLevel;
175-
if (MacroLevel == 0)
176-
State = TokenState::Start;
177-
else
178-
State = TokenState::MacroId;
179-
} else
180-
State = TokenState::MacroArguments;
181-
break;
182-
case TokenState::MacroArguments:
183-
if (isMacroIdentifier(Idents, ProtoToken))
184-
State = TokenState::MacroLeftParen;
185-
else if (ProtoToken.is(tok::TokenKind::r_paren)) {
186-
--MacroLevel;
187-
if (MacroLevel == 0)
188-
State = TokenState::Start;
189-
}
190-
break;
191-
case TokenState::LeftParen:
192-
if (ProtoToken.is(tok::TokenKind::raw_identifier)) {
193-
if (isMacroIdentifier(Idents, ProtoToken))
194-
State = TokenState::MacroId;
195-
else if (ProtoToken.getRawIdentifier() == "void") {
196-
State = TokenState::Void;
197-
VoidToken = ProtoToken;
198-
}
199-
} else if (ProtoToken.is(tok::TokenKind::l_paren))
200-
State = TokenState::LeftParen;
201-
else
202-
State = TokenState::Start;
203-
break;
204-
case TokenState::Void:
205-
State = TokenState::Start;
206-
if (ProtoToken.is(tok::TokenKind::r_paren))
207-
removeVoidToken(VoidToken, Diagnostic);
208-
else if (ProtoToken.is(tok::TokenKind::l_paren))
209-
State = TokenState::LeftParen;
210-
break;
211-
}
212-
}
213-
214-
if (State == TokenState::Void && ProtoToken.is(tok::TokenKind::r_paren))
215-
removeVoidToken(VoidToken, Diagnostic);
216-
}
217-
218-
void RedundantVoidArgCheck::removeVoidToken(Token VoidToken,
219-
StringRef Diagnostic) {
220-
const SourceLocation VoidLoc = VoidToken.getLocation();
221-
diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidLoc);
222-
}
223-
224-
void RedundantVoidArgCheck::processTypedefNameDecl(
225-
const MatchFinder::MatchResult &Result,
226-
const TypedefNameDecl *TypedefName) {
227-
if (protoTypeHasNoParms(TypedefName->getUnderlyingType()))
228-
removeVoidArgumentTokens(Result, TypedefName->getSourceRange(),
229-
isa<TypedefDecl>(TypedefName) ? "typedef"
230-
: "type alias");
231-
}
232-
233-
void RedundantVoidArgCheck::processFieldDecl(
234-
const MatchFinder::MatchResult &Result, const FieldDecl *Member) {
235-
if (protoTypeHasNoParms(Member->getType()))
236-
removeVoidArgumentTokens(Result, Member->getSourceRange(),
237-
"field declaration");
238-
}
239-
240-
void RedundantVoidArgCheck::processVarDecl(
241-
const MatchFinder::MatchResult &Result, const VarDecl *Var) {
242-
if (protoTypeHasNoParms(Var->getType())) {
243-
const SourceLocation Begin = Var->getBeginLoc();
244-
if (Var->hasInit()) {
245-
const SourceLocation InitStart =
246-
Result.SourceManager->getExpansionLoc(Var->getInit()->getBeginLoc())
247-
.getLocWithOffset(-1);
248-
removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart),
249-
"variable declaration with initializer");
250-
} else
251-
removeVoidArgumentTokens(Result, Var->getSourceRange(),
252-
"variable declaration");
253-
}
254-
}
255-
256-
void RedundantVoidArgCheck::processNamedCastExpr(
257-
const MatchFinder::MatchResult &Result, const CXXNamedCastExpr *NamedCast) {
258-
if (protoTypeHasNoParms(NamedCast->getTypeAsWritten()))
259-
removeVoidArgumentTokens(
260-
Result,
261-
NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(),
262-
"named cast");
263-
}
264-
265-
void RedundantVoidArgCheck::processExplicitCastExpr(
266-
const MatchFinder::MatchResult &Result,
267-
const ExplicitCastExpr *ExplicitCast) {
268-
if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten()))
269-
removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(),
270-
"cast expression");
271-
}
272-
273-
void RedundantVoidArgCheck::processLambdaExpr(
274-
const MatchFinder::MatchResult &Result, const LambdaExpr *Lambda) {
275-
if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 &&
276-
Lambda->hasExplicitParameters()) {
277-
const SourceManager *SM = Result.SourceManager;
278-
const TypeLoc TL =
279-
Lambda->getLambdaClass()->getLambdaTypeInfo()->getTypeLoc();
280-
removeVoidArgumentTokens(Result,
281-
{SM->getSpellingLoc(TL.getBeginLoc()),
282-
SM->getSpellingLoc(TL.getEndLoc())},
283-
"lambda expression");
284-
}
31+
const FunctionProtoTypeLoc TL = [&] {
32+
if (const auto *TL = Result.Nodes.getNodeAs<FunctionProtoTypeLoc>("fn"))
33+
return *TL;
34+
return Result.Nodes.getNodeAs<LambdaExpr>("fn")
35+
->getCallOperator()
36+
->getTypeSourceInfo()
37+
->getTypeLoc()
38+
.getAs<FunctionProtoTypeLoc>();
39+
}();
40+
41+
if (TL.getNumParams() != 0)
42+
return;
43+
44+
const std::optional<Token> Tok = utils::lexer::findNextTokenSkippingComments(
45+
Result.SourceManager->getSpellingLoc(TL.getLParenLoc()),
46+
*Result.SourceManager, getLangOpts());
47+
48+
if (!Tok || Tok->isNot(tok::raw_identifier) ||
49+
Tok->getRawIdentifier() != "void")
50+
return;
51+
52+
diag(Tok->getLocation(), "redundant void argument list")
53+
<< FixItHint::CreateRemoval(Tok->getLocation());
28554
}
28655

28756
} // namespace clang::tidy::modernize

clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANTVOIDARGCHECK_H
1111

1212
#include "../ClangTidyCheck.h"
13-
#include "clang/Lex/Token.h"
14-
15-
#include <string>
1613

1714
namespace clang::tidy::modernize {
1815

@@ -38,37 +35,6 @@ class RedundantVoidArgCheck : public ClangTidyCheck {
3835
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
3936

4037
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
41-
42-
private:
43-
void processFunctionDecl(const ast_matchers::MatchFinder::MatchResult &Result,
44-
const FunctionDecl *Function);
45-
46-
void
47-
processTypedefNameDecl(const ast_matchers::MatchFinder::MatchResult &Result,
48-
const TypedefNameDecl *Typedef);
49-
50-
void processFieldDecl(const ast_matchers::MatchFinder::MatchResult &Result,
51-
const FieldDecl *Member);
52-
53-
void processVarDecl(const ast_matchers::MatchFinder::MatchResult &Result,
54-
const VarDecl *Var);
55-
56-
void
57-
processNamedCastExpr(const ast_matchers::MatchFinder::MatchResult &Result,
58-
const CXXNamedCastExpr *NamedCast);
59-
60-
void
61-
processExplicitCastExpr(const ast_matchers::MatchFinder::MatchResult &Result,
62-
const ExplicitCastExpr *ExplicitCast);
63-
64-
void processLambdaExpr(const ast_matchers::MatchFinder::MatchResult &Result,
65-
const LambdaExpr *Lambda);
66-
67-
void
68-
removeVoidArgumentTokens(const ast_matchers::MatchFinder::MatchResult &Result,
69-
SourceRange Range, StringRef GrammarLocation);
70-
71-
void removeVoidToken(Token VoidToken, StringRef Diagnostic);
7238
};
7339

7440
} // namespace clang::tidy::modernize

clang-tools-extra/test/clang-tidy/checkers/modernize/redundant-void-arg-delayed.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
// RUN: %check_clang_tidy %s modernize-redundant-void-arg %t -- -- -fdelayed-template-parsing
22

33
int foo(void) {
4-
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
4+
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant void argument list [modernize-redundant-void-arg]
55
// CHECK-FIXES: int foo() {
66
return 0;
77
}
88

99
template <class T>
1010
struct MyFoo {
1111
int foo(void) {
12-
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
12+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list [modernize-redundant-void-arg]
1313
// CHECK-FIXES: int foo() {
1414
return 0;
1515
}
@@ -21,7 +21,7 @@ template <class T>
2121
struct MyBar {
2222
// This declaration isn't instantiated and won't be parsed 'delayed-template-parsing'.
2323
int foo(void) {
24-
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list in function definition [modernize-redundant-void-arg]
24+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant void argument list [modernize-redundant-void-arg]
2525
// CHECK-FIXES: int foo() {
2626
return 0;
2727
}

0 commit comments

Comments
 (0)