clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

RedundantVoidArgCheck.cpp
Go to the documentation of this file.
1 //===- RedundantVoidArgCheck.cpp - clang-tidy -----------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "RedundantVoidArgCheck.h"
11 #include "clang/Frontend/CompilerInstance.h"
12 #include "clang/Lex/Lexer.h"
13
14 using namespace clang::ast_matchers;
15
16 namespace clang {
17
18 namespace {
19
20 // Determine if the given QualType is a nullary function or pointer to same.
21 bool protoTypeHasNoParms(QualType QT) {
22 if (auto PT = QT->getAs<PointerType>()) {
23 QT = PT->getPointeeType();
24 }
25 if (auto *MPT = QT->getAs<MemberPointerType>()) {
26 QT = MPT->getPointeeType();
27 }
28 if (auto FP = QT->getAs<FunctionProtoType>()) {
29 return FP->getNumParams() == 0;
30 }
31 return false;
32 }
33
34 const char FunctionId[] = "function";
35 const char TypedefId[] = "typedef";
36 const char FieldId[] = "field";
37 const char VarId[] = "var";
38 const char NamedCastId[] = "named-cast";
39 const char CStyleCastId[] = "c-style-cast";
40 const char ExplicitCastId[] = "explicit-cast";
41 const char LambdaId[] = "lambda";
42
43 } // namespace
44
45 namespace tidy {
46 namespace modernize {
47
48 void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) {
49 Finder->addMatcher(functionDecl(isExpansionInMainFile(), parameterCountIs(0),
50 unless(isImplicit()), unless(isExternC()))
51 .bind(FunctionId),
52 this);
53 Finder->addMatcher(typedefDecl(isExpansionInMainFile()).bind(TypedefId),
54 this);
55 auto ParenFunctionType = parenType(innerType(functionType()));
56 auto PointerToFunctionType = pointee(ParenFunctionType);
57 auto FunctionOrMemberPointer =
58 anyOf(hasType(pointerType(PointerToFunctionType)),
59 hasType(memberPointerType(PointerToFunctionType)));
60 Finder->addMatcher(
61 fieldDecl(isExpansionInMainFile(), FunctionOrMemberPointer).bind(FieldId),
62 this);
63 Finder->addMatcher(
64 varDecl(isExpansionInMainFile(), FunctionOrMemberPointer).bind(VarId),
65 this);
66 auto CastDestinationIsFunction =
67 hasDestinationType(pointsTo(ParenFunctionType));
68 Finder->addMatcher(
69 cStyleCastExpr(isExpansionInMainFile(), CastDestinationIsFunction)
70 .bind(CStyleCastId),
71 this);
72 Finder->addMatcher(
73 cxxStaticCastExpr(isExpansionInMainFile(), CastDestinationIsFunction)
74 .bind(NamedCastId),
75 this);
76 Finder->addMatcher(
77 cxxReinterpretCastExpr(isExpansionInMainFile(), CastDestinationIsFunction)
78 .bind(NamedCastId),
79 this);
80 Finder->addMatcher(
81 cxxConstCastExpr(isExpansionInMainFile(), CastDestinationIsFunction)
82 .bind(NamedCastId),
83 this);
84 Finder->addMatcher(lambdaExpr(isExpansionInMainFile()).bind(LambdaId), this);
85 }
86
87 void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) {
88 if (!Result.Context->getLangOpts().CPlusPlus) {
89 return;
90 }
91
92 const BoundNodes &Nodes = Result.Nodes;
93 if (const auto *Function = Nodes.getNodeAs<FunctionDecl>(FunctionId)) {
94 processFunctionDecl(Result, Function);
95 } else if (const auto *Typedef = Nodes.getNodeAs<TypedefDecl>(TypedefId)) {
96 processTypedefDecl(Result, Typedef);
97 } else if (const auto *Member = Nodes.getNodeAs<FieldDecl>(FieldId)) {
98 processFieldDecl(Result, Member);
99 } else if (const auto *Var = Nodes.getNodeAs<VarDecl>(VarId)) {
100 processVarDecl(Result, Var);
101 } else if (const auto *NamedCast =
102 Nodes.getNodeAs<CXXNamedCastExpr>(NamedCastId)) {
103 processNamedCastExpr(Result, NamedCast);
104 } else if (const auto *CStyleCast =
105 Nodes.getNodeAs<CStyleCastExpr>(CStyleCastId)) {
106 processExplicitCastExpr(Result, CStyleCast);
107 } else if (const auto *ExplicitCast =
108 Nodes.getNodeAs<ExplicitCastExpr>(ExplicitCastId)) {
109 processExplicitCastExpr(Result, ExplicitCast);
110 } else if (const auto *Lambda = Nodes.getNodeAs<LambdaExpr>(LambdaId)) {
111 processLambdaExpr(Result, Lambda);
112 }
113 }
114
115 void RedundantVoidArgCheck::processFunctionDecl(
116 const MatchFinder::MatchResult &Result, const FunctionDecl *Function) {
117 SourceLocation Start = Function->getLocStart();
118 if (Function->isThisDeclarationADefinition()) {
119 SourceLocation End;
120 if (Function->hasBody())
121 End = Function->getBody()->getLocStart().getLocWithOffset(-1);
122 else
123 End = Function->getLocEnd();
124 removeVoidArgumentTokens(Result, SourceRange(Start, End),
125 "function definition");
126 } else {
127 removeVoidArgumentTokens(Result, Function->getSourceRange(),
128 "function declaration");
129 }
130 }
131
132 void RedundantVoidArgCheck::removeVoidArgumentTokens(
133 const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range,
134 StringRef GrammarLocation) {
135 CharSourceRange CharRange = Lexer::makeFileCharRange(
136 CharSourceRange::getTokenRange(Range), *Result.SourceManager,
137 Result.Context->getLangOpts());
138
139 std::string DeclText = Lexer::getSourceText(CharRange, *Result.SourceManager,
140 Result.Context->getLangOpts())
141 .str();
142 Lexer PrototypeLexer(CharRange.getBegin(), Result.Context->getLangOpts(),
143 DeclText.data(), DeclText.data(),
144 DeclText.data() + DeclText.size());
145 enum TokenState {
146 NothingYet,
147 SawLeftParen,
148 SawVoid,
149 };
150 TokenState State = NothingYet;
151 Token VoidToken;
152 Token ProtoToken;
153 std::string Diagnostic =
154 ("redundant void argument list in " + GrammarLocation).str();
155
156 while (!PrototypeLexer.LexFromRawLexer(ProtoToken)) {
157 switch (State) {
158 case NothingYet:
159 if (ProtoToken.is(tok::TokenKind::l_paren)) {
160 State = SawLeftParen;
161 }
162 break;
163 case SawLeftParen:
164 if (ProtoToken.is(tok::TokenKind::raw_identifier) &&
165 ProtoToken.getRawIdentifier() == "void") {
166 State = SawVoid;
167 VoidToken = ProtoToken;
168 } else {
169 State = NothingYet;
170 }
171 break;
172 case SawVoid:
173 State = NothingYet;
174 if (ProtoToken.is(tok::TokenKind::r_paren)) {
175 removeVoidToken(VoidToken, Diagnostic);
176 } else if (ProtoToken.is(tok::TokenKind::l_paren)) {
177 State = SawLeftParen;
178 }
179 break;
180 }
181 }
182
183 if (State == SawVoid && ProtoToken.is(tok::TokenKind::r_paren)) {
184 removeVoidToken(VoidToken, Diagnostic);
185 }
186 }
187
188 void RedundantVoidArgCheck::removeVoidToken(Token VoidToken,
189 StringRef Diagnostic) {
190 SourceLocation VoidLoc(VoidToken.getLocation());
191 auto VoidRange =
192 CharSourceRange::getTokenRange(VoidLoc, VoidLoc.getLocWithOffset(3));
193 diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange);
194 }
195
196 void RedundantVoidArgCheck::processTypedefDecl(
197 const MatchFinder::MatchResult &Result, const TypedefDecl *Typedef) {
198 if (protoTypeHasNoParms(Typedef->getUnderlyingType())) {
199 removeVoidArgumentTokens(Result, Typedef->getSourceRange(), "typedef");
200 }
201 }
202
203 void RedundantVoidArgCheck::processFieldDecl(
204 const MatchFinder::MatchResult &Result, const FieldDecl *Member) {
205 if (protoTypeHasNoParms(Member->getType())) {
206 removeVoidArgumentTokens(Result, Member->getSourceRange(),
207 "field declaration");
208 }
209 }
210
211 void RedundantVoidArgCheck::processVarDecl(
212 const MatchFinder::MatchResult &Result, const VarDecl *Var) {
213 if (protoTypeHasNoParms(Var->getType())) {
214 SourceLocation Begin = Var->getLocStart();
215 if (Var->hasInit()) {
216 SourceLocation InitStart =
217 Result.SourceManager->getExpansionLoc(Var->getInit()->getLocStart())
218 .getLocWithOffset(-1);
219 removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart),
220 "variable declaration with initializer");
221 } else {
222 removeVoidArgumentTokens(Result, Var->getSourceRange(),
223 "variable declaration");
224 }
225 }
226 }
227
228 void RedundantVoidArgCheck::processNamedCastExpr(
229 const MatchFinder::MatchResult &Result, const CXXNamedCastExpr *NamedCast) {
230 if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) {
231 removeVoidArgumentTokens(
232 Result,
233 NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(),
234 "named cast");
235 }
236 }
237
238 void RedundantVoidArgCheck::processExplicitCastExpr(
239 const MatchFinder::MatchResult &Result,
240 const ExplicitCastExpr *ExplicitCast) {
241 if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten())) {
242 removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(),
243 "cast expression");
244 }
245 }
246
247 void RedundantVoidArgCheck::processLambdaExpr(
248 const MatchFinder::MatchResult &Result, const LambdaExpr *Lambda) {
249 if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 &&
250 Lambda->hasExplicitParameters()) {
251 SourceLocation Begin =
252 Lambda->getIntroducerRange().getEnd().getLocWithOffset(1);
253 SourceLocation End = Lambda->getBody()->getLocStart().getLocWithOffset(-1);
254 removeVoidArgumentTokens(Result, SourceRange(Begin, End),
255 "lambda expression");
256 }
257 }
258
259 } // namespace modernize
260 } // namespace tidy
261 } // namespace clang
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
clang::tidy::modernize::PointerType
static const char PointerType[]
Definition: MakeUniqueCheck.cpp:21
Range
CharSourceRange Range
SourceRange for the file name.
Definition: IncludeOrderCheck.cpp:35
RedundantVoidArgCheck.h
Result
const NamedDecl * Result
Definition: USRFinder.cpp:121