diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/tools/extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/tools/extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp')
-rw-r--r-- | contrib/libs/clang16/tools/extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/contrib/libs/clang16/tools/extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp b/contrib/libs/clang16/tools/extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp new file mode 100644 index 0000000000..53447c2b96 --- /dev/null +++ b/contrib/libs/clang16/tools/extra/clang-tidy/modernize/RedundantVoidArgCheck.cpp @@ -0,0 +1,288 @@ +//===- 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 |