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

Reply via email to