10#include "clang/Frontend/CompilerInstance.h"
11#include "clang/Lex/Lexer.h"
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;
31static const char VarId[] =
"var";
38 Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()),
39 unless(isInstantiated()), unless(isExternC()))
42 Finder->addMatcher(typedefNameDecl(unless(isImplicit())).bind(
TypedefId),
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));
54 cStyleCastExpr(CastDestinationIsFunction).bind(
CStyleCastId),
this);
56 cxxStaticCastExpr(CastDestinationIsFunction).bind(
NamedCastId),
this);
58 cxxReinterpretCastExpr(CastDestinationIsFunction).bind(
NamedCastId),
61 cxxConstCastExpr(CastDestinationIsFunction).bind(
NamedCastId),
this);
62 Finder->addMatcher(lambdaExpr().bind(
LambdaId),
this);
66 const BoundNodes &Nodes = Result.Nodes;
67 if (
const auto *Function = Nodes.getNodeAs<FunctionDecl>(
FunctionId))
68 processFunctionDecl(Result, Function);
70 Nodes.getNodeAs<TypedefNameDecl>(
TypedefId))
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 =
78 processNamedCastExpr(Result, NamedCast);
79 else if (
const auto *CStyleCast =
81 processExplicitCastExpr(Result, CStyleCast);
82 else if (
const auto *ExplicitCast =
84 processExplicitCastExpr(Result, ExplicitCast);
85 else if (
const auto *Lambda = Nodes.getNodeAs<LambdaExpr>(
LambdaId))
86 processLambdaExpr(Result, Lambda);
89void RedundantVoidArgCheck::processFunctionDecl(
90 const MatchFinder::MatchResult &Result,
const FunctionDecl *Function) {
91 const auto *Method = dyn_cast<CXXMethodDecl>(Function);
92 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);
104 removeVoidArgumentTokens(Result, SourceRange(Start, End),
105 "function definition");
107 removeVoidArgumentTokens(Result, SourceRange(Start, End),
108 "function declaration");
112 const Token &ProtoToken) {
113 if (!ProtoToken.is(tok::TokenKind::raw_identifier))
116 IdentifierTable::iterator It = Idents.find(ProtoToken.getRawIdentifier());
117 if (It == Idents.end())
120 return It->second->hadMacroDefinition();
123void RedundantVoidArgCheck::removeVoidArgumentTokens(
124 const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range,
125 StringRef GrammarLocation) {
126 CharSourceRange CharRange =
127 Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Range),
128 *Result.SourceManager, getLangOpts());
130 std::string DeclText =
131 Lexer::getSourceText(CharRange, *Result.SourceManager, getLangOpts())
133 Lexer PrototypeLexer(CharRange.getBegin(), getLangOpts(), DeclText.data(),
134 DeclText.data(), DeclText.data() + DeclText.size());
135 enum class TokenState {
143 TokenState State = TokenState::Start;
146 const IdentifierTable &Idents = Result.Context->Idents;
148 std::string Diagnostic =
149 (
"redundant void argument list in " + GrammarLocation).str();
151 while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) {
153 case TokenState::Start:
154 if (ProtoToken.is(tok::TokenKind::l_paren))
155 State = TokenState::LeftParen;
157 State = TokenState::MacroId;
159 case TokenState::MacroId:
160 if (ProtoToken.is(tok::TokenKind::l_paren))
161 State = TokenState::MacroLeftParen;
163 State = TokenState::Start;
165 case TokenState::MacroLeftParen:
167 if (ProtoToken.is(tok::TokenKind::raw_identifier)) {
169 State = TokenState::MacroId;
171 State = TokenState::MacroArguments;
172 }
else if (ProtoToken.is(tok::TokenKind::r_paren)) {
175 State = TokenState::Start;
177 State = TokenState::MacroId;
179 State = TokenState::MacroArguments;
181 case TokenState::MacroArguments:
183 State = TokenState::MacroLeftParen;
184 else if (ProtoToken.is(tok::TokenKind::r_paren)) {
187 State = TokenState::Start;
190 case TokenState::LeftParen:
191 if (ProtoToken.is(tok::TokenKind::raw_identifier)) {
193 State = TokenState::MacroId;
194 else if (ProtoToken.getRawIdentifier() ==
"void") {
195 State = TokenState::Void;
196 VoidToken = ProtoToken;
198 }
else if (ProtoToken.is(tok::TokenKind::l_paren))
199 State = TokenState::LeftParen;
201 State = TokenState::Start;
203 case TokenState::Void:
204 State = TokenState::Start;
205 if (ProtoToken.is(tok::TokenKind::r_paren))
206 removeVoidToken(VoidToken, Diagnostic);
207 else if (ProtoToken.is(tok::TokenKind::l_paren))
208 State = TokenState::LeftParen;
213 if (State == TokenState::Void && ProtoToken.is(tok::TokenKind::r_paren))
214 removeVoidToken(VoidToken, Diagnostic);
217void RedundantVoidArgCheck::removeVoidToken(Token VoidToken,
218 StringRef Diagnostic) {
219 SourceLocation VoidLoc = VoidToken.getLocation();
220 diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidLoc);
223void RedundantVoidArgCheck::processTypedefNameDecl(
224 const MatchFinder::MatchResult &Result,
227 removeVoidArgumentTokens(Result,
TypedefName->getSourceRange(),
232void RedundantVoidArgCheck::processFieldDecl(
233 const MatchFinder::MatchResult &Result,
const FieldDecl *Member) {
235 removeVoidArgumentTokens(Result, Member->getSourceRange(),
236 "field declaration");
239void RedundantVoidArgCheck::processVarDecl(
240 const MatchFinder::MatchResult &Result,
const VarDecl *Var) {
242 SourceLocation Begin = Var->getBeginLoc();
243 if (Var->hasInit()) {
244 SourceLocation InitStart =
245 Result.SourceManager->getExpansionLoc(Var->getInit()->getBeginLoc())
246 .getLocWithOffset(-1);
247 removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart),
248 "variable declaration with initializer");
250 removeVoidArgumentTokens(Result, Var->getSourceRange(),
251 "variable declaration");
255void RedundantVoidArgCheck::processNamedCastExpr(
256 const MatchFinder::MatchResult &Result,
const CXXNamedCastExpr *NamedCast) {
258 removeVoidArgumentTokens(
260 NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(),
264void RedundantVoidArgCheck::processExplicitCastExpr(
265 const MatchFinder::MatchResult &Result,
266 const ExplicitCastExpr *ExplicitCast) {
268 removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(),
272void RedundantVoidArgCheck::processLambdaExpr(
273 const MatchFinder::MatchResult &Result,
const LambdaExpr *Lambda) {
274 if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 &&
275 Lambda->hasExplicitParameters()) {
276 SourceManager *SM = Result.SourceManager;
277 TypeLoc TL = Lambda->getLambdaClass()->getLambdaTypeInfo()->getTypeLoc();
278 removeVoidArgumentTokens(Result,
279 {SM->getSpellingLoc(TL.getBeginLoc()),
280 SM->getSpellingLoc(TL.getEndLoc())},
281 "lambda expression");
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static const char TypedefId[]
static const char VarId[]
static const char FunctionId[]
static const char CStyleCastId[]
static const char NamedCastId[]
static bool protoTypeHasNoParms(QualType QT)
static bool isMacroIdentifier(const IdentifierTable &Idents, const Token &ProtoToken)
static const char LambdaId[]
static const char FieldId[]
static const char ExplicitCastId[]
static constexpr llvm::StringLiteral TypedefName