https://github.com/purnima-nlp updated https://github.com/llvm/llvm-project/pull/210007
>From 4f7f0b9bde81271d1ff272160aa9c85c7297f4ae Mon Sep 17 00:00:00 2001 From: Purnima Shrivastava <[email protected]> Date: Thu, 16 Jul 2026 13:27:32 +0530 Subject: [PATCH] [clang-tidy] Fix redundant-tag check for hidden tag declarations --- .../clang-tidy/readability/CMakeLists.txt | 2 + .../readability/ReadabilityTidyModule.cpp | 4 +- .../readability/RedundantTagCheck.cpp | 81 +++++++++++++++++ .../readability/RedundantTagCheck.h | 35 ++++++++ .../checkers/readability/redundant-tag.cpp | 89 +++++++++++++++++++ 5 files changed, 210 insertions(+), 1 deletion(-) create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantTagCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantTagCheck.h create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-tag.cpp diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 8a4b5753de890..edd964354a913 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -53,6 +53,7 @@ add_clang_library(clangTidyReadabilityModule STATIC RedundantSmartptrGetCheck.cpp RedundantStringCStrCheck.cpp RedundantStringInitCheck.cpp + RedundantTagCheck.cpp RedundantTypenameCheck.cpp ReferenceToConstructedTemporaryCheck.cpp SimplifyBooleanExprCheck.cpp @@ -69,6 +70,7 @@ add_clang_library(clangTidyReadabilityModule STATIC UseConcisePreprocessorDirectivesCheck.cpp UseStdMinMaxCheck.cpp + LINK_LIBS clangTidy clangTidyUtils diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index 69b31d6711bcd..098675b376add 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -55,6 +55,7 @@ #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" +#include "RedundantTagCheck.h" #include "RedundantTypenameCheck.h" #include "ReferenceToConstructedTemporaryCheck.h" #include "SimplifyBooleanExprCheck.h" @@ -70,7 +71,6 @@ #include "UseAnyOfAllOfCheck.h" #include "UseConcisePreprocessorDirectivesCheck.h" #include "UseStdMinMaxCheck.h" - namespace clang::tidy { namespace readability { namespace { @@ -202,6 +202,8 @@ class ReadabilityModule : public ClangTidyModule { "readability-use-concise-preprocessor-directives"); CheckFactories.registerCheck<UseStdMinMaxCheck>( "readability-use-std-min-max"); + CheckFactories.registerCheck<RedundantTagCheck>( + "readability-redundant-tag"); } }; diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTagCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantTagCheck.cpp new file mode 100644 index 0000000000000..d98d7d430a080 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantTagCheck.cpp @@ -0,0 +1,81 @@ +//===--- RedundantTagCheck.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 "RedundantTagCheck.h" + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeLoc.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +static bool canHideTag(const NamedDecl *D) { + D = D->getUnderlyingDecl(); + + return isa<VarDecl>(D) || isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D) || + isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D) || + isa<UnresolvedUsingValueDecl>(D); +} + +void RedundantTagCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + typeLoc(unless(hasAncestor(decl(isInstantiated())))).bind("typeLoc"), + this); +} + +void RedundantTagCheck::check(const MatchFinder::MatchResult &Result) { + const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("typeLoc"); + if (!TL) + return; + + if (TL->getType()->isInstantiationDependentType()) + return; + + const auto TagTL = TL->getAs<TagTypeLoc>(); + if (!TagTL) + return; + + const TagDecl *TD = TagTL.getDecl(); + if (!TD) + return; + + auto Lookup = TD->getDeclContext()->lookup(TD->getDeclName()); + + for (const NamedDecl *ND : Lookup) { + if (declaresSameEntity(ND, TD)) + continue; + + if (canHideTag(ND)) + return; + } + + const SourceLocation KeywordLoc = TagTL.getElaboratedKeywordLoc(); + if (KeywordLoc.isInvalid()) + return; + + Token Tok; + if (Lexer::getRawToken(KeywordLoc, Tok, *Result.SourceManager, getLangOpts())) + return; + + const llvm::StringRef Keyword = Tok.getRawIdentifier(); + + if (Keyword != "struct" && Keyword != "class" && Keyword != "union" && + Keyword != "enum") + return; + + diag(KeywordLoc, "redundant '%0' keyword in C++ declaration") + << Keyword << FixItHint::CreateRemoval(KeywordLoc); +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/RedundantTagCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantTagCheck.h new file mode 100644 index 0000000000000..70bcdd43b7eba --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantTagCheck.h @@ -0,0 +1,35 @@ +//===--- RedundantTagCheck.h - 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTAGCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTTAGCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +class RedundantTagCheck : public ClangTidyCheck { +public: + RedundantTagCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::readability + +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-tag.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-tag.cpp new file mode 100644 index 0000000000000..4400a2f1fd08d --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-tag.cpp @@ -0,0 +1,89 @@ +// RUN: %check_clang_tidy %s readability-redundant-tag %t -- -- -std=c++20 + +struct Struct {}; +class Class {}; +union Union {}; +enum Enum {}; + +void basic() { + struct Struct s; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'struct' keyword in C++ declaration + // CHECK-FIXES: Struct s; + + class Class c; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'class' keyword in C++ declaration + // CHECK-FIXES: Class c; + + union Union u; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'union' keyword in C++ declaration + // CHECK-FIXES: Union u; + + enum Enum e; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'enum' keyword in C++ declaration + // CHECK-FIXES: Enum e; +} + +// Hidden by variable (GitHub issue) +struct Hidden {} Hidden; + +void hiddenByVariable() { + struct Hidden h; +} + +// Forward declaration +struct Forward; + +void forwardDecl() { + struct Forward *p; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'struct' keyword in C++ declaration + // CHECK-FIXES: Forward *p; +} + +// Namespace-qualified type +namespace N { +struct NS {}; +} + +void namespaceQualified() { + struct N::NS x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'struct' keyword in C++ declaration + // CHECK-FIXES: N::NS x; +} + +// Nested type +struct Outer { + struct Inner {}; +}; + +void nestedType() { + struct Outer::Inner x; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: redundant 'struct' keyword in C++ declaration + // CHECK-FIXES: Outer::Inner x; +} + +// Hidden by function +struct FuncTag {}; + +void FuncTag(); + +void hiddenByFunction() { + struct FuncTag x; +} + +// Hidden by enum constant +struct EnumTag {}; + +enum { EnumTag }; + +void hiddenByEnumConstant() { + struct EnumTag x; +} + +// Hidden by another variable +struct A {}; + +A A; + +void anotherHiddenVariable() { + struct A x; +} \ No newline at end of file _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
