summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy')
-rw-r--r--clang-tools-extra/clang-tidy/modernize/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp254
-rw-r--r--clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h76
4 files changed, 334 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index f8129767505..e14faaf877d 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -6,6 +6,7 @@ add_clang_library(clangTidyModernizeModule
MakeUniqueCheck.cpp
ModernizeTidyModule.cpp
PassByValueCheck.cpp
+ RedundantVoidArgCheck.cpp
ReplaceAutoPtrCheck.cpp
ShrinkToFitCheck.cpp
UseAutoCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index d7463abf30f..924461ca331 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -13,6 +13,7 @@
#include "LoopConvertCheck.h"
#include "MakeUniqueCheck.h"
#include "PassByValueCheck.h"
+#include "RedundantVoidArgCheck.h"
#include "ReplaceAutoPtrCheck.h"
#include "ShrinkToFitCheck.h"
#include "UseAutoCheck.h"
@@ -32,6 +33,8 @@ public:
CheckFactories.registerCheck<LoopConvertCheck>("modernize-loop-convert");
CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique");
CheckFactories.registerCheck<PassByValueCheck>("modernize-pass-by-value");
+ CheckFactories.registerCheck<RedundantVoidArgCheck>(
+ "modernize-redundant-void-arg");
CheckFactories.registerCheck<ReplaceAutoPtrCheck>(
"modernize-replace-auto-ptr");
CheckFactories.registerCheck<ShrinkToFitCheck>("modernize-shrink-to-fit");
diff --git a/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp b/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp
new file mode 100644
index 00000000000..5de65e4d101
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp
@@ -0,0 +1,254 @@
+//===- RedundantVoidArgCheck.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 "RedundantVoidArgCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+
+namespace {
+
+// Determine if the given QualType is a nullary function or pointer to same.
+bool protoTypeHasNoParms(QualType QT) {
+ if (auto PT = QT->getAs<PointerType>()) {
+ QT = PT->getPointeeType();
+ }
+ if (auto *MPT = QT->getAs<MemberPointerType>()) {
+ QT = MPT->getPointeeType();
+ }
+ if (auto FP = QT->getAs<FunctionProtoType>()) {
+ 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 LambdaId[] = "lambda";
+
+} // namespace
+
+namespace tidy {
+namespace modernize {
+
+void RedundantVoidArgCheck::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(
+ cxxStaticCastExpr(isExpansionInMainFile(), CastDestinationIsFunction)
+ .bind(NamedCastId),
+ this);
+ Finder->addMatcher(
+ cxxReinterpretCastExpr(isExpansionInMainFile(), CastDestinationIsFunction)
+ .bind(NamedCastId),
+ this);
+ Finder->addMatcher(cxxConstCastExpr(isExpansionInMainFile(),
+ CastDestinationIsFunction).bind(NamedCastId),
+ this);
+ Finder->addMatcher(lambdaExpr(isExpansionInMainFile()).bind(LambdaId), this);
+}
+
+void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) {
+ if (!Result.Context->getLangOpts().CPlusPlus) {
+ return;
+ }
+
+ const BoundNodes &Nodes = Result.Nodes;
+ if (const auto *Function = Nodes.getNodeAs<FunctionDecl>(FunctionId)) {
+ processFunctionDecl(Result, Function);
+ } else if (const auto *Typedef = Nodes.getNodeAs<TypedefDecl>(TypedefId)) {
+ processTypedefDecl(Result, Typedef);
+ } else if (const auto *Member = Nodes.getNodeAs<FieldDecl>(FieldId)) {
+ processFieldDecl(Result, Member);
+ } else if (const auto *Var = Nodes.getNodeAs<VarDecl>(VarId)) {
+ processVarDecl(Result, Var);
+ } else if (const auto *NamedCast =
+ Nodes.getNodeAs<CXXNamedCastExpr>(NamedCastId)) {
+ processNamedCastExpr(Result, NamedCast);
+ } else if (const auto *CStyleCast =
+ Nodes.getNodeAs<CStyleCastExpr>(CStyleCastId)) {
+ processExplicitCastExpr(Result, CStyleCast);
+ } else if (const auto *ExplicitCast =
+ Nodes.getNodeAs<ExplicitCastExpr>(ExplicitCastId)) {
+ processExplicitCastExpr(Result, ExplicitCast);
+ } else if (const auto *Lambda = Nodes.getNodeAs<LambdaExpr>(LambdaId)) {
+ processLambdaExpr(Result, Lambda);
+ }
+}
+
+void RedundantVoidArgCheck::processFunctionDecl(
+ const MatchFinder::MatchResult &Result, const FunctionDecl *Function) {
+ SourceLocation Start = Function->getLocStart();
+ if (Function->isThisDeclarationADefinition()) {
+ SourceLocation BeforeBody =
+ Function->getBody()->getLocStart().getLocWithOffset(-1);
+ removeVoidArgumentTokens(Result, SourceRange(Start, BeforeBody),
+ "function definition");
+ } else {
+ removeVoidArgumentTokens(Result, Function->getSourceRange(),
+ "function declaration");
+ }
+}
+
+void RedundantVoidArgCheck::removeVoidArgumentTokens(
+ const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range,
+ StringRef GrammarLocation) {
+ std::string DeclText =
+ Lexer::getSourceText(CharSourceRange::getTokenRange(Range),
+ *Result.SourceManager,
+ Result.Context->getLangOpts()).str();
+ Lexer PrototypeLexer(Range.getBegin(), 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 RedundantVoidArgCheck::removeVoidToken(Token VoidToken,
+ StringRef Diagnostic) {
+ SourceLocation VoidLoc(VoidToken.getLocation());
+ auto VoidRange =
+ CharSourceRange::getTokenRange(VoidLoc, VoidLoc.getLocWithOffset(3));
+ diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidRange);
+}
+
+void RedundantVoidArgCheck::processTypedefDecl(
+ const MatchFinder::MatchResult &Result, const TypedefDecl *Typedef) {
+ if (protoTypeHasNoParms(Typedef->getUnderlyingType())) {
+ removeVoidArgumentTokens(Result, Typedef->getSourceRange(), "typedef");
+ }
+}
+
+void RedundantVoidArgCheck::processFieldDecl(
+ const MatchFinder::MatchResult &Result, const FieldDecl *Member) {
+ if (protoTypeHasNoParms(Member->getType())) {
+ removeVoidArgumentTokens(Result, Member->getSourceRange(),
+ "field declaration");
+ }
+}
+
+void RedundantVoidArgCheck::processVarDecl(
+ const MatchFinder::MatchResult &Result, const VarDecl *Var) {
+ if (protoTypeHasNoParms(Var->getType())) {
+ SourceLocation Begin = Var->getLocStart();
+ if (Var->hasInit()) {
+ SourceLocation InitStart =
+ Result.SourceManager->getExpansionLoc(Var->getInit()->getLocStart())
+ .getLocWithOffset(-1);
+ removeVoidArgumentTokens(Result, SourceRange(Begin, InitStart),
+ "variable declaration with initializer");
+ } else {
+ removeVoidArgumentTokens(Result, Var->getSourceRange(),
+ "variable declaration");
+ }
+ }
+}
+
+void RedundantVoidArgCheck::processNamedCastExpr(
+ const MatchFinder::MatchResult &Result, const CXXNamedCastExpr *NamedCast) {
+ if (protoTypeHasNoParms(NamedCast->getTypeAsWritten())) {
+ removeVoidArgumentTokens(
+ Result,
+ NamedCast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange(),
+ "named cast");
+ }
+}
+
+void RedundantVoidArgCheck::processExplicitCastExpr(
+ const MatchFinder::MatchResult &Result,
+ const ExplicitCastExpr *ExplicitCast) {
+ if (protoTypeHasNoParms(ExplicitCast->getTypeAsWritten())) {
+ removeVoidArgumentTokens(Result, ExplicitCast->getSourceRange(),
+ "cast expression");
+ }
+}
+
+void RedundantVoidArgCheck::processLambdaExpr(
+ const MatchFinder::MatchResult &Result, const LambdaExpr *Lambda) {
+ if (Lambda->getLambdaClass()->getLambdaCallOperator()->getNumParams() == 0 &&
+ Lambda->hasExplicitParameters()) {
+ SourceLocation Begin =
+ Lambda->getIntroducerRange().getEnd().getLocWithOffset(1);
+ SourceLocation End = Lambda->getBody()->getLocStart().getLocWithOffset(-1);
+ removeVoidArgumentTokens(Result, SourceRange(Begin, End),
+ "lambda expression");
+ }
+}
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h b/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h
new file mode 100644
index 00000000000..8feb6e5075d
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/RedundantVoidArgCheck.h
@@ -0,0 +1,76 @@
+//===--- RedundantVoidArgCheck.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_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H
+
+#include "../ClangTidy.h"
+#include "clang/Lex/Token.h"
+
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// \brief Find and remove redundant void argument lists.
+///
+/// Examples:
+/// `int f(void);` becomes `int f();`
+/// `int (*f(void))(void);` becomes `int (*f())();`
+/// `typedef int (*f_t(void))(void);` becomes `typedef int (*f_t())();`
+/// `void (C::*p)(void);` becomes `void (C::*p)();`
+/// `C::C(void) {}` becomes `C::C() {}`
+/// `C::~C(void) {}` becomes `C::~C() {}`
+///
+class RedundantVoidArgCheck : public ClangTidyCheck {
+public:
+ RedundantVoidArgCheck(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
+ 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,
+ SourceRange Range, StringRef GrammarLocation);
+
+ void removeVoidToken(Token VoidToken, StringRef Diagnostic);
+};
+
+} // namespace modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_REDUNDANT_VOID_ARG_CHECK_H
OpenPOWER on IntegriCloud