123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- //===- RedundantVoidArgCheck.cpp - clang-tidy -----------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "RedundantVoidArgCheck.h"
- #include "clang/Frontend/CompilerInstance.h"
- #include "clang/Lex/Lexer.h"
- using namespace clang::ast_matchers;
- namespace clang::tidy::modernize {
- namespace {
- // Determine if the given QualType is a nullary function or pointer to same.
- bool protoTypeHasNoParms(QualType QT) {
- if (const auto *PT = QT->getAs<PointerType>())
- QT = PT->getPointeeType();
- if (auto *MPT = QT->getAs<MemberPointerType>())
- QT = MPT->getPointeeType();
- if (const 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
- void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()),
- unless(isInstantiated()), unless(isExternC()))
- .bind(FunctionId),
- this);
- Finder->addMatcher(typedefNameDecl(unless(isImplicit())).bind(TypedefId),
- this);
- auto ParenFunctionType = parenType(innerType(functionType()));
- auto PointerToFunctionType = pointee(ParenFunctionType);
- auto FunctionOrMemberPointer =
- anyOf(hasType(pointerType(PointerToFunctionType)),
- hasType(memberPointerType(PointerToFunctionType)));
- Finder->addMatcher(fieldDecl(FunctionOrMemberPointer).bind(FieldId), this);
- Finder->addMatcher(varDecl(FunctionOrMemberPointer).bind(VarId), this);
- auto CastDestinationIsFunction =
- hasDestinationType(pointsTo(ParenFunctionType));
- Finder->addMatcher(
- cStyleCastExpr(CastDestinationIsFunction).bind(CStyleCastId), this);
- Finder->addMatcher(
- cxxStaticCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
- Finder->addMatcher(
- cxxReinterpretCastExpr(CastDestinationIsFunction).bind(NamedCastId),
- this);
- Finder->addMatcher(
- cxxConstCastExpr(CastDestinationIsFunction).bind(NamedCastId), this);
- Finder->addMatcher(lambdaExpr().bind(LambdaId), this);
- }
- void RedundantVoidArgCheck::check(const MatchFinder::MatchResult &Result) {
- const BoundNodes &Nodes = Result.Nodes;
- if (const auto *Function = Nodes.getNodeAs<FunctionDecl>(FunctionId))
- processFunctionDecl(Result, Function);
- else if (const auto *TypedefName =
- Nodes.getNodeAs<TypedefNameDecl>(TypedefId))
- processTypedefNameDecl(Result, TypedefName);
- 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) {
- const auto *Method = dyn_cast<CXXMethodDecl>(Function);
- SourceLocation Start = Method && Method->getParent()->isLambda()
- ? Method->getBeginLoc()
- : Function->getLocation();
- SourceLocation End = Function->getEndLoc();
- if (Function->isThisDeclarationADefinition()) {
- if (const Stmt *Body = Function->getBody()) {
- End = Body->getBeginLoc();
- if (End.isMacroID() &&
- Result.SourceManager->isAtStartOfImmediateMacroExpansion(End))
- End = Result.SourceManager->getExpansionLoc(End);
- End = End.getLocWithOffset(-1);
- }
- removeVoidArgumentTokens(Result, SourceRange(Start, End),
- "function definition");
- } else
- removeVoidArgumentTokens(Result, SourceRange(Start, End),
- "function declaration");
- }
- bool isMacroIdentifier(const IdentifierTable &Idents, const Token &ProtoToken) {
- if (!ProtoToken.is(tok::TokenKind::raw_identifier))
- return false;
- IdentifierTable::iterator It = Idents.find(ProtoToken.getRawIdentifier());
- if (It == Idents.end())
- return false;
- return It->second->hadMacroDefinition();
- }
- void RedundantVoidArgCheck::removeVoidArgumentTokens(
- const ast_matchers::MatchFinder::MatchResult &Result, SourceRange Range,
- StringRef GrammarLocation) {
- CharSourceRange CharRange =
- Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Range),
- *Result.SourceManager, getLangOpts());
- std::string DeclText =
- Lexer::getSourceText(CharRange, *Result.SourceManager, getLangOpts())
- .str();
- Lexer PrototypeLexer(CharRange.getBegin(), getLangOpts(), DeclText.data(),
- DeclText.data(), DeclText.data() + DeclText.size());
- enum class TokenState {
- Start,
- MacroId,
- MacroLeftParen,
- MacroArguments,
- LeftParen,
- Void,
- };
- TokenState State = TokenState::Start;
- Token VoidToken;
- Token ProtoToken;
- const 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 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 = 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 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 = TokenState::LeftParen;
- else
- State = TokenState::Start;
- break;
- 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 = TokenState::LeftParen;
- break;
- }
- }
- if (State == TokenState::Void && ProtoToken.is(tok::TokenKind::r_paren))
- removeVoidToken(VoidToken, Diagnostic);
- }
- void RedundantVoidArgCheck::removeVoidToken(Token VoidToken,
- StringRef Diagnostic) {
- SourceLocation VoidLoc = VoidToken.getLocation();
- diag(VoidLoc, Diagnostic) << FixItHint::CreateRemoval(VoidLoc);
- }
- void RedundantVoidArgCheck::processTypedefNameDecl(
- const MatchFinder::MatchResult &Result,
- const TypedefNameDecl *TypedefName) {
- if (protoTypeHasNoParms(TypedefName->getUnderlyingType()))
- removeVoidArgumentTokens(Result, TypedefName->getSourceRange(),
- isa<TypedefDecl>(TypedefName) ? "typedef"
- : "type alias");
- }
- 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->getBeginLoc();
- if (Var->hasInit()) {
- SourceLocation InitStart =
- Result.SourceManager->getExpansionLoc(Var->getInit()->getBeginLoc())
- .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()) {
- SourceManager *SM = Result.SourceManager;
- TypeLoc TL = Lambda->getLambdaClass()->getLambdaTypeInfo()->getTypeLoc();
- removeVoidArgumentTokens(Result,
- {SM->getSpellingLoc(TL.getBeginLoc()),
- SM->getSpellingLoc(TL.getEndLoc())},
- "lambda expression");
- }
- }
- } // namespace clang::tidy::modernize
|