[clang-tools-extra] [clang-tidy] Treat fields in anonymous records as names in enclosing scope when checking name styles (PR #75701)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 26 03:56:15 PST 2023
https://github.com/Lancern updated https://github.com/llvm/llvm-project/pull/75701
>From 5d04ca8091fc81fad8e33355a0afcce290bf34f0 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Sat, 16 Dec 2023 21:55:24 +0800
Subject: [PATCH 1/5] [clang-tidy] Check anonymous record field naming in
enclosing scopes
Currently, fields in anonymous records are regarded as normal fields when
checking their name styles. Naming rules for class/struct/union member apply to
these fields. This commit changes this behavior:
- If the anonymous record is defined within the file scope or in a namespace
scope, treat its fields as global variables when checking name styles;
- If the anonymous record is defined within a function, treat its fields as
local variables when checking name styles;
- If the anonymous record is defined within a non-anonymous record, treat its
fields as non-static record members when checking name styles.
---
.../readability/IdentifierNamingCheck.cpp | 196 ++++++++++--------
.../readability/IdentifierNamingCheck.h | 13 ++
.../clang-tidy/utils/ASTUtils.cpp | 24 +++
clang-tools-extra/clang-tidy/utils/ASTUtils.h | 5 +
.../identifier-naming-anon-record-fields.cpp | 184 ++++++++++++++++
5 files changed, 341 insertions(+), 81 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index 03dcfa5f811095..0e18712fd27564 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -9,6 +9,7 @@
#include "IdentifierNamingCheck.h"
#include "../GlobList.h"
+#include "../utils/ASTUtils.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
@@ -1185,29 +1186,12 @@ StyleKind IdentifierNamingCheck::findStyleKind(
}
if (const auto *Decl = dyn_cast<FieldDecl>(D)) {
- QualType Type = Decl->getType();
-
- if (!Type.isNull() && Type.isConstQualified()) {
- if (NamingStyles[SK_ConstantMember])
- return SK_ConstantMember;
-
- if (NamingStyles[SK_Constant])
- return SK_Constant;
+ const RecordDecl *Record = Decl->getParent();
+ if (Record->isAnonymousStructOrUnion()) {
+ return findStyleKindForAnonField(Decl, NamingStyles);
}
- if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMember])
- return SK_PrivateMember;
-
- if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember])
- return SK_ProtectedMember;
-
- if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember])
- return SK_PublicMember;
-
- if (NamingStyles[SK_Member])
- return SK_Member;
-
- return SK_Invalid;
+ return findStyleKindForField(Decl, Decl->getType(), NamingStyles);
}
if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {
@@ -1244,66 +1228,7 @@ StyleKind IdentifierNamingCheck::findStyleKind(
}
if (const auto *Decl = dyn_cast<VarDecl>(D)) {
- QualType Type = Decl->getType();
-
- if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])
- return SK_ConstexprVariable;
-
- if (!Type.isNull() && Type.isConstQualified()) {
- if (Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant])
- return SK_ClassConstant;
-
- if (Decl->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
- NamingStyles[SK_GlobalConstantPointer])
- return SK_GlobalConstantPointer;
-
- if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant])
- return SK_GlobalConstant;
-
- if (Decl->isStaticLocal() && NamingStyles[SK_StaticConstant])
- return SK_StaticConstant;
-
- if (Decl->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
- NamingStyles[SK_LocalConstantPointer])
- return SK_LocalConstantPointer;
-
- if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant])
- return SK_LocalConstant;
-
- if (Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant])
- return SK_LocalConstant;
-
- if (NamingStyles[SK_Constant])
- return SK_Constant;
- }
-
- if (Decl->isStaticDataMember() && NamingStyles[SK_ClassMember])
- return SK_ClassMember;
-
- if (Decl->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
- NamingStyles[SK_GlobalPointer])
- return SK_GlobalPointer;
-
- if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable])
- return SK_GlobalVariable;
-
- if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable])
- return SK_StaticVariable;
-
- if (Decl->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
- NamingStyles[SK_LocalPointer])
- return SK_LocalPointer;
-
- if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable])
- return SK_LocalVariable;
-
- if (Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable])
- return SK_LocalVariable;
-
- if (NamingStyles[SK_Variable])
- return SK_Variable;
-
- return SK_Invalid;
+ return findStyleKindForVar(Decl, Decl->getType(), NamingStyles);
}
if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {
@@ -1496,5 +1421,114 @@ IdentifierNamingCheck::getStyleForFile(StringRef FileName) const {
return It.first->getValue();
}
+StyleKind IdentifierNamingCheck::findStyleKindForAnonField(
+ const FieldDecl *AnonField,
+ ArrayRef<std::optional<NamingStyle>> NamingStyles) const {
+ const IndirectFieldDecl *IFD =
+ utils::findOutermostIndirectFieldDeclForField(AnonField);
+ assert(IFD && "Found an anonymous record field without an IndirectFieldDecl");
+
+ QualType Type = AnonField->getType();
+
+ if (const auto *F = dyn_cast<FieldDecl>(IFD->chain().front())) {
+ return findStyleKindForField(F, Type, NamingStyles);
+ }
+
+ if (const auto *V = IFD->getVarDecl()) {
+ return findStyleKindForVar(V, Type, NamingStyles);
+ }
+
+ return SK_Invalid;
+}
+
+StyleKind IdentifierNamingCheck::findStyleKindForField(
+ const FieldDecl *Field, QualType Type,
+ ArrayRef<std::optional<NamingStyle>> NamingStyles) const {
+ if (!Type.isNull() && Type.isConstQualified()) {
+ if (NamingStyles[SK_ConstantMember])
+ return SK_ConstantMember;
+
+ if (NamingStyles[SK_Constant])
+ return SK_Constant;
+ }
+
+ if (Field->getAccess() == AS_private && NamingStyles[SK_PrivateMember])
+ return SK_PrivateMember;
+
+ if (Field->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember])
+ return SK_ProtectedMember;
+
+ if (Field->getAccess() == AS_public && NamingStyles[SK_PublicMember])
+ return SK_PublicMember;
+
+ if (NamingStyles[SK_Member])
+ return SK_Member;
+
+ return SK_Invalid;
+}
+
+StyleKind IdentifierNamingCheck::findStyleKindForVar(
+ const VarDecl *Var, QualType Type,
+ ArrayRef<std::optional<NamingStyle>> NamingStyles) const {
+ if (Var->isConstexpr() && NamingStyles[SK_ConstexprVariable])
+ return SK_ConstexprVariable;
+
+ if (!Type.isNull() && Type.isConstQualified()) {
+ if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstant])
+ return SK_ClassConstant;
+
+ if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+ NamingStyles[SK_GlobalConstantPointer])
+ return SK_GlobalConstantPointer;
+
+ if (Var->isFileVarDecl() && NamingStyles[SK_GlobalConstant])
+ return SK_GlobalConstant;
+
+ if (Var->isStaticLocal() && NamingStyles[SK_StaticConstant])
+ return SK_StaticConstant;
+
+ if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+ NamingStyles[SK_LocalConstantPointer])
+ return SK_LocalConstantPointer;
+
+ if (Var->isLocalVarDecl() && NamingStyles[SK_LocalConstant])
+ return SK_LocalConstant;
+
+ if (Var->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant])
+ return SK_LocalConstant;
+
+ if (NamingStyles[SK_Constant])
+ return SK_Constant;
+ }
+
+ if (Var->isStaticDataMember() && NamingStyles[SK_ClassMember])
+ return SK_ClassMember;
+
+ if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+ NamingStyles[SK_GlobalPointer])
+ return SK_GlobalPointer;
+
+ if (Var->isFileVarDecl() && NamingStyles[SK_GlobalVariable])
+ return SK_GlobalVariable;
+
+ if (Var->isStaticLocal() && NamingStyles[SK_StaticVariable])
+ return SK_StaticVariable;
+
+ if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
+ NamingStyles[SK_LocalPointer])
+ return SK_LocalPointer;
+
+ if (Var->isLocalVarDecl() && NamingStyles[SK_LocalVariable])
+ return SK_LocalVariable;
+
+ if (Var->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable])
+ return SK_LocalVariable;
+
+ if (NamingStyles[SK_Variable])
+ return SK_Variable;
+
+ return SK_Invalid;
+}
+
} // namespace readability
} // namespace clang::tidy
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
index 14626981cc42d8..c3918120ccd3e8 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
@@ -199,6 +199,19 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck {
const FileStyle &getStyleForFile(StringRef FileName) const;
+ /// Find the style kind of a field in an anonymous record.
+ StyleKind findStyleKindForAnonField(
+ const FieldDecl *AnonField,
+ ArrayRef<std::optional<NamingStyle>> NamingStyles) const;
+
+ StyleKind findStyleKindForField(
+ const FieldDecl *Field, QualType Type,
+ ArrayRef<std::optional<NamingStyle>> NamingStyles) const;
+
+ StyleKind
+ findStyleKindForVar(const VarDecl *Var, QualType Type,
+ ArrayRef<std::optional<NamingStyle>> NamingStyles) const;
+
/// Stores the style options as a vector, indexed by the specified \ref
/// StyleKind, for a given directory.
mutable llvm::StringMap<FileStyle> NamingStylesCache;
diff --git a/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp b/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
index 64333f2c187454..fd5dadc9b01db1 100644
--- a/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
@@ -113,4 +113,28 @@ bool areStatementsIdentical(const Stmt *FirstStmt, const Stmt *SecondStmt,
return DataFirst == DataSecond;
}
+const IndirectFieldDecl *
+findOutermostIndirectFieldDeclForField(const FieldDecl *FD) {
+ const RecordDecl *Record = FD->getParent();
+ assert(Record->isAnonymousStructOrUnion() &&
+ "FD must be a field in an anonymous record");
+
+ const DeclContext *Context = Record;
+ while (isa<RecordDecl>(Context) &&
+ cast<RecordDecl>(Context)->isAnonymousStructOrUnion()) {
+ Context = Context->getParent();
+ }
+
+ // Search for the target IndirectFieldDecl within the located context.
+ for (const auto *D : Context->decls()) {
+ const auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+ if (!IFD)
+ continue;
+ if (IFD->getAnonField() == FD)
+ return IFD;
+ }
+
+ return nullptr;
+}
+
} // namespace clang::tidy::utils
diff --git a/clang-tools-extra/clang-tidy/utils/ASTUtils.h b/clang-tools-extra/clang-tidy/utils/ASTUtils.h
index 1bba5daf2fc765..6c3e54facd0202 100644
--- a/clang-tools-extra/clang-tidy/utils/ASTUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/ASTUtils.h
@@ -40,6 +40,11 @@ bool rangeCanBeFixed(SourceRange Range, const SourceManager *SM);
bool areStatementsIdentical(const Stmt *FirstStmt, const Stmt *SecondStmt,
const ASTContext &Context, bool Canonical = false);
+// Given a field of an anonymous record, find its corresponding
+// IndirectFieldDecl in the outermost possible scope.
+const IndirectFieldDecl *
+findOutermostIndirectFieldDeclForField(const FieldDecl *FD);
+
} // namespace clang::tidy::utils
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ASTUTILS_H
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp
new file mode 100644
index 00000000000000..9da160b4c68956
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp
@@ -0,0 +1,184 @@
+// RUN: %check_clang_tidy -std=c++20 %s readability-identifier-naming %t -- \
+// RUN: -config='{CheckOptions: { \
+// RUN: readability-identifier-naming.ClassConstantCase: CamelCase, \
+// RUN: readability-identifier-naming.ClassConstantPrefix: 'k', \
+// RUN: readability-identifier-naming.ClassMemberCase: CamelCase, \
+// RUN: readability-identifier-naming.ConstantCase: UPPER_CASE, \
+// RUN: readability-identifier-naming.ConstantSuffix: '_CST', \
+// RUN: readability-identifier-naming.ConstexprVariableCase: lower_case, \
+// RUN: readability-identifier-naming.GlobalConstantCase: UPPER_CASE, \
+// RUN: readability-identifier-naming.GlobalVariableCase: lower_case, \
+// RUN: readability-identifier-naming.GlobalVariablePrefix: 'g_', \
+// RUN: readability-identifier-naming.LocalConstantCase: CamelCase, \
+// RUN: readability-identifier-naming.LocalConstantPrefix: 'k', \
+// RUN: readability-identifier-naming.LocalVariableCase: lower_case, \
+// RUN: readability-identifier-naming.MemberCase: CamelCase, \
+// RUN: readability-identifier-naming.MemberPrefix: 'm_', \
+// RUN: readability-identifier-naming.ConstantMemberCase: lower_case, \
+// RUN: readability-identifier-naming.PrivateMemberPrefix: '__', \
+// RUN: readability-identifier-naming.ProtectedMemberPrefix: '_', \
+// RUN: readability-identifier-naming.PublicMemberCase: lower_case, \
+// RUN: readability-identifier-naming.StaticConstantCase: UPPER_CASE, \
+// RUN: readability-identifier-naming.StaticVariableCase: camelBack, \
+// RUN: readability-identifier-naming.StaticVariablePrefix: 's_', \
+// RUN: readability-identifier-naming.VariableCase: lower_case, \
+// RUN: readability-identifier-naming.GlobalPointerCase: CamelCase, \
+// RUN: readability-identifier-naming.GlobalPointerSuffix: '_Ptr', \
+// RUN: readability-identifier-naming.GlobalConstantPointerCase: UPPER_CASE, \
+// RUN: readability-identifier-naming.GlobalConstantPointerSuffix: '_Ptr', \
+// RUN: readability-identifier-naming.LocalPointerCase: CamelCase, \
+// RUN: readability-identifier-naming.LocalPointerPrefix: 'l_', \
+// RUN: readability-identifier-naming.LocalConstantPointerCase: CamelCase, \
+// RUN: readability-identifier-naming.LocalConstantPointerPrefix: 'lc_', \
+// RUN: }}'
+
+static union {
+ int global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'global'
+// CHECK-FIXES: {{^}} int g_global;{{$}}
+
+ const int global_const;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global constant 'global_const'
+// CHECK-FIXES: {{^}} const int GLOBAL_CONST;{{$}}
+
+ int *global_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'global_ptr'
+// CHECK-FIXES: {{^}} int *GlobalPtr_Ptr;{{$}}
+
+ int *const global_const_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global constant pointer 'global_const_ptr'
+// CHECK-FIXES: {{^}} int *const GLOBAL_CONST_PTR_Ptr;{{$}}
+};
+
+namespace ns {
+
+static union {
+ int ns_global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'ns_global'
+// CHECK-FIXES: {{^}} int g_ns_global;{{$}}
+
+ const int ns_global_const;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global constant 'ns_global_const'
+// CHECK-FIXES: {{^}} const int NS_GLOBAL_CONST;{{$}}
+
+ int *ns_global_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'ns_global_ptr'
+// CHECK-FIXES: {{^}} int *NsGlobalPtr_Ptr;{{$}}
+
+ int *const ns_global_const_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global constant pointer 'ns_global_const_ptr'
+// CHECK-FIXES: {{^}} int *const NS_GLOBAL_CONST_PTR_Ptr;{{$}}
+};
+
+namespace {
+
+union {
+ int anon_ns_global;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for global variable 'anon_ns_global'
+// CHECK-FIXES: {{^}} int g_anon_ns_global;{{$}}
+
+ const int anon_ns_global_const;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: invalid case style for global constant 'anon_ns_global_const'
+// CHECK-FIXES: {{^}} const int ANON_NS_GLOBAL_CONST;{{$}}
+
+ int *anon_ns_global_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: invalid case style for global pointer 'anon_ns_global_ptr'
+// CHECK-FIXES: {{^}} int *AnonNsGlobalPtr_Ptr;{{$}}
+
+ int *const anon_ns_global_const_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global constant pointer 'anon_ns_global_const_ptr'
+// CHECK-FIXES: {{^}} int *const ANON_NS_GLOBAL_CONST_PTR_Ptr;{{$}}
+};
+
+}
+
+}
+
+
+class Foo {
+public:
+ union {
+ int PubMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for public member 'PubMember'
+// CHECK-FIXES: {{^}} int pub_member;{{$}}
+
+ const int PubConstMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for constant member 'PubConstMember'
+// CHECK-FIXES: {{^}} const int pub_const_member;{{$}}
+
+ int *PubPtrMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for public member 'PubPtrMember'
+// CHECK-FIXES: {{^}} int *pub_ptr_member;{{$}}
+
+ int *const PubConstPtrMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for constant member 'PubConstPtrMember'
+// CHECK-FIXES: {{^}} int *const pub_const_ptr_member;{{$}}
+ };
+
+protected:
+ union {
+ int prot_member;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for protected member 'prot_member'
+// CHECK-FIXES: {{^}} int _prot_member;{{$}}
+
+ const int prot_const_member;
+
+ int *prot_ptr_member;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for protected member 'prot_ptr_member'
+// CHECK-FIXES: {{^}} int *_prot_ptr_member;{{$}}
+
+ int *const prot_const_ptr_member;
+ };
+
+
+private:
+ union {
+ int pri_member;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for private member 'pri_member'
+// CHECK-FIXES: {{^}} int __pri_member;{{$}}
+
+ const int pri_const_member;
+
+ int *pri_ptr_member;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for private member 'pri_ptr_member'
+// CHECK-FIXES: {{^}} int *__pri_ptr_member;{{$}}
+
+ int *const pri_const_ptr_member;
+ };
+};
+
+void test() {
+ union {
+ int local;
+
+ const int local_const;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for local constant 'local_const'
+// CHECK-FIXES: {{^}} const int kLocalConst;{{$}}
+
+ int *local_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for local pointer 'local_ptr'
+// CHECK-FIXES: {{^}} int *l_LocalPtr;{{$}}
+
+ int *const local_const_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for local constant pointer 'local_const_ptr'
+// CHECK-FIXES: {{^}} int *const lc_LocalConstPtr;{{$}}
+ };
+
+ static union {
+ int local_static;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for static variable 'local_static'
+// CHECK-FIXES: {{^}} int s_localStatic;{{$}}
+
+ const int local_static_const;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: invalid case style for static constant 'local_static_const'
+// CHECK-FIXES: {{^}} const int LOCAL_STATIC_CONST;{{$}}
+
+ int *local_static_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for static variable 'local_static_ptr'
+// CHECK-FIXES: {{^}} int *s_localStaticPtr;{{$}}
+
+ int *const local_static_const_ptr;
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for static constant 'local_static_const_ptr'
+// CHECK-FIXES: {{^}} int *const LOCAL_STATIC_CONST_PTR;{{$}}
+ };
+}
>From e04473764c287f1e17993b24bf9895b11c80361d Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Sat, 16 Dec 2023 22:37:17 +0800
Subject: [PATCH 2/5] [clang-tidy] add CheckAnonFieldInParent option to naming
check
---
.../readability/IdentifierNamingCheck.cpp | 29 ++++++++++++-------
.../readability/IdentifierNamingCheck.h | 13 +++++++--
.../identifier-naming-anon-record-fields.cpp | 1 +
3 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
index 0e18712fd27564..e6f44dd51b4596 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -287,7 +287,9 @@ IdentifierNamingCheck::FileStyle IdentifierNamingCheck::getFileStyleFromOptions(
HPTOpt.value_or(IdentifierNamingCheck::HPT_Off));
}
bool IgnoreMainLike = Options.get("IgnoreMainLikeFunctions", false);
- return {std::move(Styles), std::move(HNOption), IgnoreMainLike};
+ bool CheckAnonFieldInParent = Options.get("CheckAnonFieldInParent", false);
+ return {std::move(Styles), std::move(HNOption), IgnoreMainLike,
+ CheckAnonFieldInParent};
}
std::string IdentifierNamingCheck::HungarianNotation::getDeclTypeName(
@@ -860,6 +862,8 @@ void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
Options.store(Opts, "IgnoreMainLikeFunctions",
MainFileStyle->isIgnoringMainLikeFunction());
+ Options.store(Opts, "CheckAnonFieldInParent",
+ MainFileStyle->isCheckingAnonFieldInParentScope());
}
bool IdentifierNamingCheck::matchesStyle(
@@ -1112,7 +1116,7 @@ std::string IdentifierNamingCheck::fixupWithStyle(
StyleKind IdentifierNamingCheck::findStyleKind(
const NamedDecl *D,
ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles,
- bool IgnoreMainLikeFunctions) const {
+ bool IgnoreMainLikeFunctions, bool CheckAnonFieldInParentScope) const {
assert(D && D->getIdentifier() && !D->getName().empty() && !D->isImplicit() &&
"Decl must be an explicit identifier with a name.");
@@ -1186,9 +1190,11 @@ StyleKind IdentifierNamingCheck::findStyleKind(
}
if (const auto *Decl = dyn_cast<FieldDecl>(D)) {
- const RecordDecl *Record = Decl->getParent();
- if (Record->isAnonymousStructOrUnion()) {
- return findStyleKindForAnonField(Decl, NamingStyles);
+ if (CheckAnonFieldInParentScope) {
+ const RecordDecl *Record = Decl->getParent();
+ if (Record->isAnonymousStructOrUnion()) {
+ return findStyleKindForAnonField(Decl, NamingStyles);
+ }
}
return findStyleKindForField(Decl, Decl->getType(), NamingStyles);
@@ -1367,12 +1373,13 @@ IdentifierNamingCheck::getDeclFailureInfo(const NamedDecl *Decl,
if (!FileStyle.isActive())
return std::nullopt;
- return getFailureInfo(HungarianNotation.getDeclTypeName(Decl),
- Decl->getName(), Decl, Loc, FileStyle.getStyles(),
- FileStyle.getHNOption(),
- findStyleKind(Decl, FileStyle.getStyles(),
- FileStyle.isIgnoringMainLikeFunction()),
- SM, IgnoreFailedSplit);
+ return getFailureInfo(
+ HungarianNotation.getDeclTypeName(Decl), Decl->getName(), Decl, Loc,
+ FileStyle.getStyles(), FileStyle.getHNOption(),
+ findStyleKind(Decl, FileStyle.getStyles(),
+ FileStyle.isIgnoringMainLikeFunction(),
+ FileStyle.isCheckingAnonFieldInParentScope()),
+ SM, IgnoreFailedSplit);
}
std::optional<RenamerClangTidyCheck::FailureInfo>
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
index c3918120ccd3e8..27c8e4bc768c40 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h
@@ -127,9 +127,11 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck {
struct FileStyle {
FileStyle() : IsActive(false), IgnoreMainLikeFunctions(false) {}
FileStyle(SmallVectorImpl<std::optional<NamingStyle>> &&Styles,
- HungarianNotationOption HNOption, bool IgnoreMainLike)
+ HungarianNotationOption HNOption, bool IgnoreMainLike,
+ bool CheckAnonFieldInParent)
: Styles(std::move(Styles)), HNOption(std::move(HNOption)),
- IsActive(true), IgnoreMainLikeFunctions(IgnoreMainLike) {}
+ IsActive(true), IgnoreMainLikeFunctions(IgnoreMainLike),
+ CheckAnonFieldInParentScope(CheckAnonFieldInParent) {}
ArrayRef<std::optional<NamingStyle>> getStyles() const {
assert(IsActive);
@@ -144,11 +146,16 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck {
bool isActive() const { return IsActive; }
bool isIgnoringMainLikeFunction() const { return IgnoreMainLikeFunctions; }
+ bool isCheckingAnonFieldInParentScope() const {
+ return CheckAnonFieldInParentScope;
+ }
+
private:
SmallVector<std::optional<NamingStyle>, 0> Styles;
HungarianNotationOption HNOption;
bool IsActive;
bool IgnoreMainLikeFunctions;
+ bool CheckAnonFieldInParentScope;
};
IdentifierNamingCheck::FileStyle
@@ -175,7 +182,7 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck {
StyleKind findStyleKind(
const NamedDecl *D,
ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles,
- bool IgnoreMainLikeFunctions) const;
+ bool IgnoreMainLikeFunctions, bool CheckAnonFieldInParentScope) const;
std::optional<RenamerClangTidyCheck::FailureInfo> getFailureInfo(
StringRef Type, StringRef Name, const NamedDecl *ND,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp
index 9da160b4c68956..1b4d4e924a7217 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-anon-record-fields.cpp
@@ -1,5 +1,6 @@
// RUN: %check_clang_tidy -std=c++20 %s readability-identifier-naming %t -- \
// RUN: -config='{CheckOptions: { \
+// RUN: readability-identifier-naming.CheckAnonFieldInParent: true, \
// RUN: readability-identifier-naming.ClassConstantCase: CamelCase, \
// RUN: readability-identifier-naming.ClassConstantPrefix: 'k', \
// RUN: readability-identifier-naming.ClassMemberCase: CamelCase, \
>From 17738275a4cfd51a26aa44152b3ea93911b57971 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Sun, 17 Dec 2023 00:16:57 +0800
Subject: [PATCH 3/5] [clang-tidy] update documentation and release notes
---
clang-tools-extra/docs/ReleaseNotes.rst | 5 ++++
.../checks/readability/identifier-naming.rst | 26 +++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6d91748e4cef18..3b33545e538c4b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -128,6 +128,11 @@ Improvements to clang-tidy
as a value for `-export-fixes` to export individual yaml files for each
compilation unit.
+- A new option `readability-identifier-naming.CheckAnonFieldInParent` is added. When set
+ to `true`, fields of anonymous records (i.e. anonymous unions and structs) will be
+ treated either as a variable or as a field in the enclosing scope for the purpose of
+ name style checking.
+
New checks
^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
index e36bbee394f17a..1a17ff90b7c8bf 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
@@ -42,6 +42,7 @@ The following options are described below:
- :option:`AbstractClassCase`, :option:`AbstractClassPrefix`, :option:`AbstractClassSuffix`, :option:`AbstractClassIgnoredRegexp`, :option:`AbstractClassHungarianPrefix`
- :option:`AggressiveDependentMemberLookup`
+ - :option:`CheckAnonFieldInParent`
- :option:`ClassCase`, :option:`ClassPrefix`, :option:`ClassSuffix`, :option:`ClassIgnoredRegexp`, :option:`ClassHungarianPrefix`
- :option:`ClassConstantCase`, :option:`ClassConstantPrefix`, :option:`ClassConstantSuffix`, :option:`ClassConstantIgnoredRegexp`, :option:`ClassConstantHungarianPrefix`
- :option:`ClassMemberCase`, :option:`ClassMemberPrefix`, :option:`ClassMemberSuffix`, :option:`ClassMemberIgnoredRegexp`, :option:`ClassMemberHungarianPrefix`
@@ -207,6 +208,31 @@ After if AggressiveDependentMemberLookup is `true`:
}
};
+.. option:: CheckAnonFieldInParent
+
+ When set to `true`, fields in anonymous records (i.e. anonymous
+ unions and structs) will be treated as names in the enclosing scope
+ rather than public members of the anonymous record for the purpose
+ of name checking.
+
+For example:
+
+.. code-block:: c++
+
+ class Foo {
+ private:
+ union {
+ int iv_;
+ float fv_;
+ };
+ };
+
+If CheckAnonFieldInParent is `false`, you may get warnings that ``iv_`` and
+``fv_`` are not coherent to public member names, because ``iv_`` and ``fv_``
+are public members of the anonymous union. When CheckAnonFieldInParent is
+`true`, ``iv_`` and ``fv_`` will be treated as private data members of ``Foo``
+for the purpose of name checking and thus no warnings will be emitted.
+
.. option:: ClassCase
When defined, the check will ensure class names conform to the
>From 35059453e7db984a66081d5eefd77f57e1dd9c91 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Sun, 17 Dec 2023 09:42:51 +0800
Subject: [PATCH 4/5] [clang-tidy] update release notes according to review
---
clang-tools-extra/docs/ReleaseNotes.rst | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3b33545e538c4b..9b30ef6f4f0c6c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -128,11 +128,6 @@ Improvements to clang-tidy
as a value for `-export-fixes` to export individual yaml files for each
compilation unit.
-- A new option `readability-identifier-naming.CheckAnonFieldInParent` is added. When set
- to `true`, fields of anonymous records (i.e. anonymous unions and structs) will be
- treated either as a variable or as a field in the enclosing scope for the purpose of
- name style checking.
-
New checks
^^^^^^^^^^
@@ -446,7 +441,10 @@ Changes in existing checks
has been enhanced, particularly within complex types like function pointers
and cases where style checks were omitted when functions started with macros.
Added support for C++20 ``concept`` declarations. ``Camel_Snake_Case`` and
- ``camel_Snake_Case`` now detect more invalid identifier names.
+ ``camel_Snake_Case`` now detect more invalid identifier names. Fields in
+ anonymous records (i.e. anonymous structs and unions) now can be checked with
+ the naming rules associated with their enclosing scopes rather than the naming
+ rules of public struct/union members.
- Improved :doc:`readability-implicit-bool-conversion
<clang-tidy/checks/readability/implicit-bool-conversion>` check to take
>From 4425e06d3deecdd68ec1ce623e89f05c12914bdf Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Tue, 26 Dec 2023 10:02:55 +0800
Subject: [PATCH 5/5] Update docs according to review
---
.../checks/readability/identifier-naming.rst | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
index 1a17ff90b7c8bf..2affb55cfa9ad7 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst
@@ -227,11 +227,12 @@ For example:
};
};
-If CheckAnonFieldInParent is `false`, you may get warnings that ``iv_`` and
-``fv_`` are not coherent to public member names, because ``iv_`` and ``fv_``
-are public members of the anonymous union. When CheckAnonFieldInParent is
-`true`, ``iv_`` and ``fv_`` will be treated as private data members of ``Foo``
-for the purpose of name checking and thus no warnings will be emitted.
+If :option:`CheckAnonFieldInParent` is `false`, you may get warnings
+that ``iv_`` and ``fv_`` are not coherent to public member names, because
+``iv_`` and ``fv_`` are public members of the anonymous union. When
+:option:`CheckAnonFieldInParent` is `true`, ``iv_`` and ``fv_`` will be
+treated as private data members of ``Foo`` for the purpose of name checking
+and thus no warnings will be emitted.
.. option:: ClassCase
More information about the cfe-commits
mailing list