1 //===--- IdentifierNamingCheck.cpp - clang-tidy ---------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "IdentifierNamingCheck.h"
11 #include "../GlobList.h"
12 #include "../utils/ASTUtils.h"
13 #include "clang/AST/CXXInheritance.h"
14 #include "clang/Lex/PPCallbacks.h"
15 #include "clang/Lex/Preprocessor.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/DenseMapInfo.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Debug.h"
20 #include "llvm/Support/Error.h"
21 #include "llvm/Support/FormatVariadic.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/Regex.h"
24 #include "llvm/Support/YAMLParser.h"
27 #define DEBUG_TYPE "clang-tidy"
31 using namespace clang::ast_matchers
;
33 namespace clang::tidy
{
36 std::pair
<readability::IdentifierNamingCheck::CaseType
, StringRef
>>
38 readability::IdentifierNamingCheck::CaseType
>::getEnumMapping() {
39 static constexpr std::pair
<readability::IdentifierNamingCheck::CaseType
,
42 {readability::IdentifierNamingCheck::CT_AnyCase
, "aNy_CasE"},
43 {readability::IdentifierNamingCheck::CT_LowerCase
, "lower_case"},
44 {readability::IdentifierNamingCheck::CT_UpperCase
, "UPPER_CASE"},
45 {readability::IdentifierNamingCheck::CT_CamelBack
, "camelBack"},
46 {readability::IdentifierNamingCheck::CT_CamelCase
, "CamelCase"},
47 {readability::IdentifierNamingCheck::CT_CamelSnakeCase
,
49 {readability::IdentifierNamingCheck::CT_CamelSnakeBack
,
51 {readability::IdentifierNamingCheck::CT_LeadingUpperSnakeCase
,
52 "Leading_upper_snake_case"}};
57 struct OptionEnumMapping
<
58 readability::IdentifierNamingCheck::HungarianPrefixType
> {
59 using HungarianPrefixType
=
60 readability::IdentifierNamingCheck::HungarianPrefixType
;
61 static llvm::ArrayRef
<std::pair
<HungarianPrefixType
, StringRef
>>
63 static constexpr std::pair
<HungarianPrefixType
, StringRef
> Mapping
[] = {
64 {HungarianPrefixType::HPT_Off
, "Off"},
65 {HungarianPrefixType::HPT_On
, "On"},
66 {HungarianPrefixType::HPT_LowerCase
, "LowerCase"},
67 {HungarianPrefixType::HPT_CamelCase
, "CamelCase"}};
72 namespace readability
{
75 #define NAMING_KEYS(m) \
79 m(ScopedEnumConstant) \
80 m(ConstexprVariable) \
89 m(GlobalConstantPointer) \
93 m(LocalConstantPointer) \
100 m(ConstantParameter) \
103 m(PointerParameter) \
104 m(ConstantPointerParameter) \
111 m(ConstexprFunction) \
121 m(TypeTemplateParameter) \
122 m(ValueTemplateParameter) \
123 m(TemplateTemplateParameter) \
124 m(TemplateParameter) \
130 enum StyleKind : int {
131 #define ENUMERATE(v) SK_ ## v,
132 NAMING_KEYS(ENUMERATE
)
138 static StringRef
const StyleNames
[] = {
139 #define STRINGIZE(v) #v,
140 NAMING_KEYS(STRINGIZE
)
144 #define HUNGARIAN_NOTATION_PRIMITIVE_TYPES(m) \
168 m(signed-short-int) \
169 m(signed-long-long-int) \
170 m(signed-long-long) \
174 m(unsigned-long-long-int) \
175 m(unsigned-long-long) \
176 m(unsigned-long-int) \
178 m(unsigned-short-int) \
191 static StringRef const HungarainNotationPrimitiveTypes[] = {
192 #define STRINGIZE(v) #v,
193 HUNGARIAN_NOTATION_PRIMITIVE_TYPES(STRINGIZE
)
197 #define HUNGARIAN_NOTATION_USER_DEFINED_TYPES(m) \
227 static StringRef const HungarainNotationUserDefinedTypes[] = {
228 #define STRINGIZE(v) #v,
229 HUNGARIAN_NOTATION_USER_DEFINED_TYPES(STRINGIZE
)
237 IdentifierNamingCheck::NamingStyle::NamingStyle(
238 std::optional
<IdentifierNamingCheck::CaseType
> Case
, StringRef Prefix
,
239 StringRef Suffix
, StringRef IgnoredRegexpStr
, HungarianPrefixType HPType
)
240 : Case(Case
), Prefix(Prefix
), Suffix(Suffix
),
241 IgnoredRegexpStr(IgnoredRegexpStr
), HPType(HPType
) {
242 if (!IgnoredRegexpStr
.empty()) {
244 llvm::Regex(llvm::SmallString
<128>({"^", IgnoredRegexpStr
, "$"}));
245 if (!IgnoredRegexp
.isValid())
246 llvm::errs() << "Invalid IgnoredRegexp regular expression: "
251 IdentifierNamingCheck::FileStyle
IdentifierNamingCheck::getFileStyleFromOptions(
252 const ClangTidyCheck::OptionsView
&Options
) const {
253 IdentifierNamingCheck::HungarianNotationOption HNOption
;
255 HungarianNotation
.loadDefaultConfig(HNOption
);
256 HungarianNotation
.loadFileConfig(Options
, HNOption
);
258 SmallVector
<std::optional
<IdentifierNamingCheck::NamingStyle
>, 0> Styles
;
259 Styles
.resize(SK_Count
);
260 SmallString
<64> StyleString
;
261 for (unsigned I
= 0; I
< SK_Count
; ++I
) {
262 size_t StyleSize
= StyleNames
[I
].size();
263 StyleString
.assign({StyleNames
[I
], "HungarianPrefix"});
266 Options
.get
<IdentifierNamingCheck::HungarianPrefixType
>(StyleString
);
267 if (HPTOpt
&& !HungarianNotation
.checkOptionValid(I
))
268 configurationDiag("invalid identifier naming option '%0'") << StyleString
;
270 memcpy(&StyleString
[StyleSize
], "IgnoredRegexp", 13);
271 StyleString
.truncate(StyleSize
+ 13);
272 std::optional
<StringRef
> IgnoredRegexpStr
= Options
.get(StyleString
);
273 memcpy(&StyleString
[StyleSize
], "Prefix", 6);
274 StyleString
.truncate(StyleSize
+ 6);
275 std::optional
<StringRef
> Prefix(Options
.get(StyleString
));
276 // Fast replacement of [Pre]fix -> [Suf]fix.
277 memcpy(&StyleString
[StyleSize
], "Suf", 3);
278 std::optional
<StringRef
> Postfix(Options
.get(StyleString
));
279 memcpy(&StyleString
[StyleSize
], "Case", 4);
280 StyleString
.pop_back_n(2);
281 std::optional
<CaseType
> CaseOptional
=
282 Options
.get
<IdentifierNamingCheck::CaseType
>(StyleString
);
284 if (CaseOptional
|| Prefix
|| Postfix
|| IgnoredRegexpStr
|| HPTOpt
)
285 Styles
[I
].emplace(std::move(CaseOptional
), Prefix
.value_or(""),
286 Postfix
.value_or(""), IgnoredRegexpStr
.value_or(""),
287 HPTOpt
.value_or(IdentifierNamingCheck::HPT_Off
));
289 bool IgnoreMainLike
= Options
.get("IgnoreMainLikeFunctions", false);
290 bool CheckAnonFieldInParent
= Options
.get("CheckAnonFieldInParent", false);
291 return {std::move(Styles
), std::move(HNOption
), IgnoreMainLike
,
292 CheckAnonFieldInParent
};
295 std::string
IdentifierNamingCheck::HungarianNotation::getDeclTypeName(
296 const NamedDecl
*ND
) const {
297 const auto *VD
= dyn_cast
<ValueDecl
>(ND
);
301 if (isa
<FunctionDecl
, EnumConstantDecl
>(ND
))
304 // Get type text of variable declarations.
305 auto &SM
= VD
->getASTContext().getSourceManager();
306 const char *Begin
= SM
.getCharacterData(VD
->getBeginLoc());
307 const char *End
= SM
.getCharacterData(VD
->getEndLoc());
308 intptr_t StrLen
= End
- Begin
;
310 // FIXME: Sometimes the value that returns from ValDecl->getEndLoc()
311 // is wrong(out of location of Decl). This causes `StrLen` will be assigned
312 // an unexpected large value. Current workaround to find the terminated
313 // character instead of the `getEndLoc()` function.
314 const char *EOL
= strchr(Begin
, '\n');
316 EOL
= Begin
+ strlen(Begin
);
318 const char *PosList
[] = {strchr(Begin
, '='), strchr(Begin
, ';'),
319 strchr(Begin
, ','), strchr(Begin
, ')'), EOL
};
320 for (const auto &Pos
: PosList
) {
322 EOL
= std::min(EOL
, Pos
);
325 StrLen
= EOL
- Begin
;
326 std::string TypeName
;
328 std::string
Type(Begin
, StrLen
);
330 static constexpr StringRef Keywords
[] = {
331 // Constexpr specifiers
332 "constexpr", "constinit", "consteval",
334 "const", "volatile", "restrict", "mutable",
335 // Storage class specifiers
336 "register", "static", "extern", "thread_local",
341 for (StringRef Kw
: Keywords
) {
343 (Pos
= Type
.find(Kw
.data(), Pos
)) != std::string::npos
;) {
344 Type
.replace(Pos
, Kw
.size(), "");
347 TypeName
= Type
.erase(0, Type
.find_first_not_of(' '));
349 // Remove template parameters
350 const size_t Pos
= Type
.find('<');
351 if (Pos
!= std::string::npos
) {
352 TypeName
= Type
.erase(Pos
, Type
.size() - Pos
);
355 // Replace spaces with single space.
356 for (size_t Pos
= 0; (Pos
= Type
.find(" ", Pos
)) != std::string::npos
;
357 Pos
+= strlen(" ")) {
358 Type
.replace(Pos
, strlen(" "), " ");
361 // Replace " &" with "&".
362 for (size_t Pos
= 0; (Pos
= Type
.find(" &", Pos
)) != std::string::npos
;
363 Pos
+= strlen("&")) {
364 Type
.replace(Pos
, strlen(" &"), "&");
367 // Replace " *" with "* ".
368 for (size_t Pos
= 0; (Pos
= Type
.find(" *", Pos
)) != std::string::npos
;
369 Pos
+= strlen("*")) {
370 Type
.replace(Pos
, strlen(" *"), "* ");
373 // Remove redundant tailing.
374 static constexpr StringRef TailsOfMultiWordType
[] = {
375 " int", " char", " double", " long", " short"};
376 bool RedundantRemoved
= false;
377 for (auto Kw
: TailsOfMultiWordType
) {
378 size_t Pos
= Type
.rfind(Kw
.data());
379 if (Pos
!= std::string::npos
) {
380 const size_t PtrCount
= getAsteriskCount(Type
, ND
);
381 Type
= Type
.substr(0, Pos
+ Kw
.size() + PtrCount
);
382 RedundantRemoved
= true;
387 TypeName
= Type
.erase(0, Type
.find_first_not_of(' '));
388 if (!RedundantRemoved
) {
389 std::size_t FoundSpace
= Type
.find(' ');
390 if (FoundSpace
!= std::string::npos
)
391 Type
= Type
.substr(0, FoundSpace
);
394 TypeName
= Type
.erase(0, Type
.find_first_not_of(' '));
396 QualType QT
= VD
->getType();
397 if (!QT
.isNull() && QT
->isArrayType())
398 TypeName
.append("[]");
404 IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name
,
405 ClangTidyContext
*Context
)
406 : RenamerClangTidyCheck(Name
, Context
), Context(Context
),
407 GetConfigPerFile(Options
.get("GetConfigPerFile", true)),
408 IgnoreFailedSplit(Options
.get("IgnoreFailedSplit", false)) {
410 auto IterAndInserted
= NamingStylesCache
.try_emplace(
411 llvm::sys::path::parent_path(Context
->getCurrentFile()),
412 getFileStyleFromOptions(Options
));
413 assert(IterAndInserted
.second
&& "Couldn't insert Style");
414 // Holding a reference to the data in the vector is safe as it should never
416 MainFileStyle
= &IterAndInserted
.first
->getValue();
419 IdentifierNamingCheck::~IdentifierNamingCheck() = default;
421 bool IdentifierNamingCheck::HungarianNotation::checkOptionValid(
422 int StyleKindIndex
) const {
423 if ((StyleKindIndex
>= SK_EnumConstant
) &&
424 (StyleKindIndex
<= SK_ConstantParameter
))
427 if ((StyleKindIndex
>= SK_Parameter
) && (StyleKindIndex
<= SK_Enum
))
433 bool IdentifierNamingCheck::HungarianNotation::isOptionEnabled(
434 StringRef OptionKey
, const llvm::StringMap
<std::string
> &StrMap
) const {
435 if (OptionKey
.empty())
438 auto Iter
= StrMap
.find(OptionKey
);
439 if (Iter
== StrMap
.end())
442 return *llvm::yaml::parseBool(Iter
->getValue());
445 void IdentifierNamingCheck::HungarianNotation::loadFileConfig(
446 const ClangTidyCheck::OptionsView
&Options
,
447 IdentifierNamingCheck::HungarianNotationOption
&HNOption
) const {
449 static constexpr StringRef HNOpts
[] = {"TreatStructAsClass"};
450 static constexpr StringRef HNDerivedTypes
[] = {"Array", "Pointer",
453 StringRef Section
= "HungarianNotation.";
455 SmallString
<128> Buffer
= {Section
, "General."};
456 size_t DefSize
= Buffer
.size();
457 for (const auto &Opt
: HNOpts
) {
458 Buffer
.truncate(DefSize
);
460 StringRef Val
= Options
.get(Buffer
, "");
462 HNOption
.General
[Opt
] = Val
.str();
465 Buffer
= {Section
, "DerivedType."};
466 DefSize
= Buffer
.size();
467 for (const auto &Type
: HNDerivedTypes
) {
468 Buffer
.truncate(DefSize
);
470 StringRef Val
= Options
.get(Buffer
, "");
472 HNOption
.DerivedType
[Type
] = Val
.str();
475 static constexpr std::pair
<StringRef
, StringRef
> HNCStrings
[] = {
476 {"CharPointer", "char*"},
477 {"CharArray", "char[]"},
478 {"WideCharPointer", "wchar_t*"},
479 {"WideCharArray", "wchar_t[]"}};
481 Buffer
= {Section
, "CString."};
482 DefSize
= Buffer
.size();
483 for (const auto &CStr
: HNCStrings
) {
484 Buffer
.truncate(DefSize
);
485 Buffer
.append(CStr
.first
);
486 StringRef Val
= Options
.get(Buffer
, "");
488 HNOption
.CString
[CStr
.second
] = Val
.str();
491 Buffer
= {Section
, "PrimitiveType."};
492 DefSize
= Buffer
.size();
493 for (const auto &PrimType
: HungarainNotationPrimitiveTypes
) {
494 Buffer
.truncate(DefSize
);
495 Buffer
.append(PrimType
);
496 StringRef Val
= Options
.get(Buffer
, "");
498 std::string Type
= PrimType
.str();
499 std::replace(Type
.begin(), Type
.end(), '-', ' ');
500 HNOption
.PrimitiveType
[Type
] = Val
.str();
504 Buffer
= {Section
, "UserDefinedType."};
505 DefSize
= Buffer
.size();
506 for (const auto &Type
: HungarainNotationUserDefinedTypes
) {
507 Buffer
.truncate(DefSize
);
509 StringRef Val
= Options
.get(Buffer
, "");
511 HNOption
.UserDefinedType
[Type
] = Val
.str();
515 std::string
IdentifierNamingCheck::HungarianNotation::getPrefix(
517 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
) const {
520 const auto *ND
= dyn_cast
<NamedDecl
>(D
);
525 if (const auto *ECD
= dyn_cast
<EnumConstantDecl
>(ND
)) {
526 Prefix
= getEnumPrefix(ECD
);
527 } else if (const auto *CRD
= dyn_cast
<CXXRecordDecl
>(ND
)) {
528 Prefix
= getClassPrefix(CRD
, HNOption
);
529 } else if (isa
<VarDecl
, FieldDecl
, RecordDecl
>(ND
)) {
530 std::string TypeName
= getDeclTypeName(ND
);
531 if (!TypeName
.empty())
532 Prefix
= getDataTypePrefix(TypeName
, ND
, HNOption
);
538 bool IdentifierNamingCheck::HungarianNotation::removeDuplicatedPrefix(
539 SmallVector
<StringRef
, 8> &Words
,
540 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
) const {
541 if (Words
.size() <= 1)
544 std::string CorrectName
= Words
[0].str();
545 std::vector
<llvm::StringMap
<std::string
>> MapList
= {
546 HNOption
.CString
, HNOption
.DerivedType
, HNOption
.PrimitiveType
,
547 HNOption
.UserDefinedType
};
549 for (const auto &Map
: MapList
) {
550 for (const auto &Str
: Map
) {
551 if (Str
.getValue() == CorrectName
) {
552 Words
.erase(Words
.begin(), Words
.begin() + 1);
561 std::string
IdentifierNamingCheck::HungarianNotation::getDataTypePrefix(
562 StringRef TypeName
, const NamedDecl
*ND
,
563 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
) const {
564 if (!ND
|| TypeName
.empty())
565 return TypeName
.str();
567 std::string
ModifiedTypeName(TypeName
);
570 std::string PrefixStr
;
571 if (const auto *TD
= dyn_cast
<ValueDecl
>(ND
)) {
572 QualType QT
= TD
->getType();
573 if (QT
->isFunctionPointerType()) {
574 PrefixStr
= HNOption
.DerivedType
.lookup("FunctionPointer");
575 } else if (QT
->isPointerType()) {
576 for (const auto &CStr
: HNOption
.CString
) {
577 std::string Key
= CStr
.getKey().str();
578 if (ModifiedTypeName
.find(Key
) == 0) {
579 PrefixStr
= CStr
.getValue();
580 ModifiedTypeName
= ModifiedTypeName
.substr(
581 Key
.size(), ModifiedTypeName
.size() - Key
.size());
585 } else if (QT
->isArrayType()) {
586 for (const auto &CStr
: HNOption
.CString
) {
587 std::string Key
= CStr
.getKey().str();
588 if (ModifiedTypeName
.find(Key
) == 0) {
589 PrefixStr
= CStr
.getValue();
593 if (PrefixStr
.empty())
594 PrefixStr
= HNOption
.DerivedType
.lookup("Array");
595 } else if (QT
->isReferenceType()) {
596 size_t Pos
= ModifiedTypeName
.find_last_of('&');
597 if (Pos
!= std::string::npos
)
598 ModifiedTypeName
= ModifiedTypeName
.substr(0, Pos
);
603 size_t PtrCount
= getAsteriskCount(ModifiedTypeName
);
605 ModifiedTypeName
= [&](std::string Str
, StringRef From
, StringRef To
) {
607 while ((StartPos
= Str
.find(From
.data(), StartPos
)) !=
609 Str
.replace(StartPos
, From
.size(), To
.data());
610 StartPos
+= To
.size();
613 }(ModifiedTypeName
, "*", "");
617 if (PrefixStr
.empty()) {
618 for (const auto &Type
: HNOption
.PrimitiveType
) {
619 if (ModifiedTypeName
== Type
.getKey()) {
620 PrefixStr
= Type
.getValue();
626 // User-Defined types
627 if (PrefixStr
.empty()) {
628 for (const auto &Type
: HNOption
.UserDefinedType
) {
629 if (ModifiedTypeName
== Type
.getKey()) {
630 PrefixStr
= Type
.getValue();
636 for (size_t Idx
= 0; Idx
< PtrCount
; Idx
++)
637 PrefixStr
.insert(0, HNOption
.DerivedType
.lookup("Pointer"));
642 std::string
IdentifierNamingCheck::HungarianNotation::getClassPrefix(
643 const CXXRecordDecl
*CRD
,
644 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
) const {
649 if (CRD
->isStruct() &&
650 !isOptionEnabled("TreatStructAsClass", HNOption
.General
))
653 return CRD
->isAbstract() ? "I" : "C";
656 std::string
IdentifierNamingCheck::HungarianNotation::getEnumPrefix(
657 const EnumConstantDecl
*ECD
) const {
658 const auto *ED
= cast
<EnumDecl
>(ECD
->getDeclContext());
660 std::string Name
= ED
->getName().str();
661 if (StringRef(Name
).contains("enum")) {
662 Name
= Name
.substr(strlen("enum"), Name
.length() - strlen("enum"));
663 Name
= Name
.erase(0, Name
.find_first_not_of(' '));
666 static llvm::Regex
Splitter(
667 "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
669 StringRef
EnumName(Name
);
670 SmallVector
<StringRef
, 8> Substrs
;
671 EnumName
.split(Substrs
, "_", -1, false);
673 SmallVector
<StringRef
, 8> Words
;
674 SmallVector
<StringRef
, 8> Groups
;
675 for (auto Substr
: Substrs
) {
676 while (!Substr
.empty()) {
678 if (!Splitter
.match(Substr
, &Groups
))
681 if (!Groups
[2].empty()) {
682 Words
.push_back(Groups
[1]);
683 Substr
= Substr
.substr(Groups
[0].size());
684 } else if (!Groups
[3].empty()) {
685 Words
.push_back(Groups
[3]);
686 Substr
= Substr
.substr(Groups
[0].size() - Groups
[4].size());
687 } else if (!Groups
[5].empty()) {
688 Words
.push_back(Groups
[5]);
689 Substr
= Substr
.substr(Groups
[0].size() - Groups
[6].size());
695 for (StringRef Word
: Words
)
696 Initial
+= tolower(Word
[0]);
701 size_t IdentifierNamingCheck::HungarianNotation::getAsteriskCount(
702 const std::string
&TypeName
) const {
703 size_t Pos
= TypeName
.find('*');
705 for (; Pos
< TypeName
.length(); Pos
++, Count
++) {
706 if ('*' != TypeName
[Pos
])
712 size_t IdentifierNamingCheck::HungarianNotation::getAsteriskCount(
713 const std::string
&TypeName
, const NamedDecl
*ND
) const {
715 if (const auto *TD
= dyn_cast
<ValueDecl
>(ND
)) {
716 QualType QT
= TD
->getType();
717 if (QT
->isPointerType())
718 PtrCount
= getAsteriskCount(TypeName
);
723 void IdentifierNamingCheck::HungarianNotation::loadDefaultConfig(
724 IdentifierNamingCheck::HungarianNotationOption
&HNOption
) const {
727 static constexpr std::pair
<StringRef
, StringRef
> General
[] = {
728 {"TreatStructAsClass", "false"}};
729 for (const auto &G
: General
)
730 HNOption
.General
.try_emplace(G
.first
, G
.second
);
733 static constexpr std::pair
<StringRef
, StringRef
> DerivedTypes
[] = {
734 {"Array", "a"}, {"Pointer", "p"}, {"FunctionPointer", "fn"}};
735 for (const auto &DT
: DerivedTypes
)
736 HNOption
.DerivedType
.try_emplace(DT
.first
, DT
.second
);
739 static constexpr std::pair
<StringRef
, StringRef
> CStrings
[] = {
743 {"wchar_t[]", "wsz"}};
744 for (const auto &CStr
: CStrings
)
745 HNOption
.CString
.try_emplace(CStr
.first
, CStr
.second
);
748 static constexpr std::pair
<StringRef
, StringRef
> PrimitiveTypes
[] = {
754 {"uint16_t", "u16" },
755 {"uint32_t", "u32" },
756 {"uint64_t", "u64" },
758 {"char16_t", "c16" },
759 {"char32_t", "c32" },
768 {"short int", "si" },
770 {"signed int", "si" },
771 {"signed short", "ss" },
772 {"signed short int", "ssi" },
773 {"signed long long int", "slli"},
774 {"signed long long", "sll" },
775 {"signed long int", "sli" },
776 {"signed long", "sl" },
778 {"unsigned long long int", "ulli"},
779 {"unsigned long long", "ull" },
780 {"unsigned long int", "uli" },
781 {"unsigned long", "ul" },
782 {"unsigned short int", "usi" },
783 {"unsigned short", "us" },
784 {"unsigned int", "ui" },
785 {"unsigned char", "uc" },
787 {"long long int", "lli" },
788 {"long double", "ld" },
789 {"long long", "ll" },
795 for (const auto &PT
: PrimitiveTypes
)
796 HNOption
.PrimitiveType
.try_emplace(PT
.first
, PT
.second
);
799 static constexpr std::pair
<StringRef
, StringRef
> UserDefinedTypes
[] = {
800 // Windows data types
816 {"ULONGLONG", "ull" },
830 for (const auto &UDT
: UserDefinedTypes
)
831 HNOption
.UserDefinedType
.try_emplace(UDT
.first
, UDT
.second
);
834 void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap
&Opts
) {
835 RenamerClangTidyCheck::storeOptions(Opts
);
836 SmallString
<64> StyleString
;
837 ArrayRef
<std::optional
<NamingStyle
>> Styles
= MainFileStyle
->getStyles();
838 for (size_t I
= 0; I
< SK_Count
; ++I
) {
841 size_t StyleSize
= StyleNames
[I
].size();
842 StyleString
.assign({StyleNames
[I
], "HungarianPrefix"});
844 Options
.store(Opts
, StyleString
, Styles
[I
]->HPType
);
846 memcpy(&StyleString
[StyleSize
], "IgnoredRegexp", 13);
847 StyleString
.truncate(StyleSize
+ 13);
848 Options
.store(Opts
, StyleString
, Styles
[I
]->IgnoredRegexpStr
);
849 memcpy(&StyleString
[StyleSize
], "Prefix", 6);
850 StyleString
.truncate(StyleSize
+ 6);
851 Options
.store(Opts
, StyleString
, Styles
[I
]->Prefix
);
852 // Fast replacement of [Pre]fix -> [Suf]fix.
853 memcpy(&StyleString
[StyleSize
], "Suf", 3);
854 Options
.store(Opts
, StyleString
, Styles
[I
]->Suffix
);
855 if (Styles
[I
]->Case
) {
856 memcpy(&StyleString
[StyleSize
], "Case", 4);
857 StyleString
.pop_back_n(2);
858 Options
.store(Opts
, StyleString
, *Styles
[I
]->Case
);
861 Options
.store(Opts
, "GetConfigPerFile", GetConfigPerFile
);
862 Options
.store(Opts
, "IgnoreFailedSplit", IgnoreFailedSplit
);
863 Options
.store(Opts
, "IgnoreMainLikeFunctions",
864 MainFileStyle
->isIgnoringMainLikeFunction());
865 Options
.store(Opts
, "CheckAnonFieldInParent",
866 MainFileStyle
->isCheckingAnonFieldInParentScope());
869 bool IdentifierNamingCheck::matchesStyle(
870 StringRef Type
, StringRef Name
,
871 const IdentifierNamingCheck::NamingStyle
&Style
,
872 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
,
873 const NamedDecl
*Decl
) const {
874 static llvm::Regex Matchers
[] = {
876 llvm::Regex("^[a-z][a-z0-9_]*$"),
877 llvm::Regex("^[a-z][a-zA-Z0-9]*$"),
878 llvm::Regex("^[A-Z][A-Z0-9_]*$"),
879 llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
880 llvm::Regex("^[A-Z]+([a-z0-9]*_[A-Z0-9]+)*[a-z0-9]*$"),
881 llvm::Regex("^[a-z]+([a-z0-9]*_[A-Z0-9]+)*[a-z0-9]*$"),
882 llvm::Regex("^[A-Z]([a-z0-9_]*[a-z])*$"),
885 if (!Name
.consume_front(Style
.Prefix
))
887 if (!Name
.consume_back(Style
.Suffix
))
889 if (IdentifierNamingCheck::HungarianPrefixType::HPT_Off
!= Style
.HPType
) {
890 std::string HNPrefix
= HungarianNotation
.getPrefix(Decl
, HNOption
);
891 if (!HNPrefix
.empty()) {
892 if (!Name
.consume_front(HNPrefix
))
895 IdentifierNamingCheck::HungarianPrefixType::HPT_LowerCase
&&
896 !Name
.consume_front("_"))
901 // Ensure the name doesn't have any extra underscores beyond those specified
902 // in the prefix and suffix.
903 if (Name
.starts_with("_") || Name
.ends_with("_"))
906 if (Style
.Case
&& !Matchers
[static_cast<size_t>(*Style
.Case
)].match(Name
))
912 std::string
IdentifierNamingCheck::fixupWithCase(
913 StringRef Type
, StringRef Name
, const Decl
*D
,
914 const IdentifierNamingCheck::NamingStyle
&Style
,
915 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
,
916 IdentifierNamingCheck::CaseType Case
) const {
917 static llvm::Regex
Splitter(
918 "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
920 SmallVector
<StringRef
, 8> Substrs
;
921 Name
.split(Substrs
, "_", -1, false);
923 SmallVector
<StringRef
, 8> Words
;
924 SmallVector
<StringRef
, 8> Groups
;
925 for (auto Substr
: Substrs
) {
926 while (!Substr
.empty()) {
928 if (!Splitter
.match(Substr
, &Groups
))
931 if (!Groups
[2].empty()) {
932 Words
.push_back(Groups
[1]);
933 Substr
= Substr
.substr(Groups
[0].size());
934 } else if (!Groups
[3].empty()) {
935 Words
.push_back(Groups
[3]);
936 Substr
= Substr
.substr(Groups
[0].size() - Groups
[4].size());
937 } else if (!Groups
[5].empty()) {
938 Words
.push_back(Groups
[5]);
939 Substr
= Substr
.substr(Groups
[0].size() - Groups
[6].size());
947 if (IdentifierNamingCheck::HungarianPrefixType::HPT_Off
!= Style
.HPType
) {
948 HungarianNotation
.removeDuplicatedPrefix(Words
, HNOption
);
951 SmallString
<128> Fixup
;
953 case IdentifierNamingCheck::CT_AnyCase
:
957 case IdentifierNamingCheck::CT_LowerCase
:
958 for (auto const &Word
: Words
) {
959 if (&Word
!= &Words
.front())
961 Fixup
+= Word
.lower();
965 case IdentifierNamingCheck::CT_UpperCase
:
966 for (auto const &Word
: Words
) {
967 if (&Word
!= &Words
.front())
969 Fixup
+= Word
.upper();
973 case IdentifierNamingCheck::CT_CamelCase
:
974 for (auto const &Word
: Words
) {
975 Fixup
+= toupper(Word
.front());
976 Fixup
+= Word
.substr(1).lower();
980 case IdentifierNamingCheck::CT_CamelBack
:
981 for (auto const &Word
: Words
) {
982 if (&Word
== &Words
.front()) {
983 Fixup
+= Word
.lower();
985 Fixup
+= toupper(Word
.front());
986 Fixup
+= Word
.substr(1).lower();
991 case IdentifierNamingCheck::CT_CamelSnakeCase
:
992 for (auto const &Word
: Words
) {
993 if (&Word
!= &Words
.front())
995 Fixup
+= toupper(Word
.front());
996 Fixup
+= Word
.substr(1).lower();
1000 case IdentifierNamingCheck::CT_CamelSnakeBack
:
1001 for (auto const &Word
: Words
) {
1002 if (&Word
!= &Words
.front()) {
1004 Fixup
+= toupper(Word
.front());
1006 Fixup
+= tolower(Word
.front());
1008 Fixup
+= Word
.substr(1).lower();
1012 case IdentifierNamingCheck::CT_LeadingUpperSnakeCase
:
1013 for (auto const &Word
: Words
) {
1014 if (&Word
!= &Words
.front()) {
1016 Fixup
+= Word
.lower();
1018 Fixup
+= toupper(Word
.front());
1019 Fixup
+= Word
.substr(1).lower();
1025 return Fixup
.str().str();
1028 bool IdentifierNamingCheck::isParamInMainLikeFunction(
1029 const ParmVarDecl
&ParmDecl
, bool IncludeMainLike
) const {
1031 dyn_cast_or_null
<FunctionDecl
>(ParmDecl
.getParentFunctionOrMethod());
1034 if (FDecl
->isMain())
1036 if (!IncludeMainLike
)
1038 if (FDecl
->getAccess() != AS_public
&& FDecl
->getAccess() != AS_none
)
1040 // If the function doesn't have a name that's an identifier, can occur if the
1041 // function is an operator overload, bail out early.
1042 if (!FDecl
->getDeclName().isIdentifier())
1044 enum MainType
{ None
, Main
, WMain
};
1045 auto IsCharPtrPtr
= [](QualType QType
) -> MainType
{
1048 if (QType
= QType
->getPointeeType(), QType
.isNull())
1050 if (QType
= QType
->getPointeeType(), QType
.isNull())
1052 if (QType
->isCharType())
1054 if (QType
->isWideCharType())
1058 auto IsIntType
= [](QualType QType
) {
1061 if (const auto *Builtin
=
1062 dyn_cast
<BuiltinType
>(QType
->getUnqualifiedDesugaredType())) {
1063 return Builtin
->getKind() == BuiltinType::Int
;
1067 if (!IsIntType(FDecl
->getReturnType()))
1069 if (FDecl
->getNumParams() < 2 || FDecl
->getNumParams() > 3)
1071 if (!IsIntType(FDecl
->parameters()[0]->getType()))
1073 MainType Type
= IsCharPtrPtr(FDecl
->parameters()[1]->getType());
1076 if (FDecl
->getNumParams() == 3 &&
1077 IsCharPtrPtr(FDecl
->parameters()[2]->getType()) != Type
)
1081 static llvm::Regex
Matcher(
1082 "(^[Mm]ain([_A-Z]|$))|([a-z0-9_]Main([_A-Z]|$))|(_main(_|$))");
1083 assert(Matcher
.isValid() && "Invalid Matcher for main like functions.");
1084 return Matcher
.match(FDecl
->getName());
1086 static llvm::Regex
Matcher("(^((W[Mm])|(wm))ain([_A-Z]|$))|([a-z0-9_]W[Mm]"
1087 "ain([_A-Z]|$))|(_wmain(_|$))");
1088 assert(Matcher
.isValid() && "Invalid Matcher for wmain like functions.");
1089 return Matcher
.match(FDecl
->getName());
1092 std::string
IdentifierNamingCheck::fixupWithStyle(
1093 StringRef Type
, StringRef Name
,
1094 const IdentifierNamingCheck::NamingStyle
&Style
,
1095 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
,
1096 const Decl
*D
) const {
1097 Name
.consume_front(Style
.Prefix
);
1098 Name
.consume_back(Style
.Suffix
);
1099 std::string Fixed
= fixupWithCase(
1100 Type
, Name
, D
, Style
, HNOption
,
1101 Style
.Case
.value_or(IdentifierNamingCheck::CaseType::CT_AnyCase
));
1103 std::string HungarianPrefix
;
1104 using HungarianPrefixType
= IdentifierNamingCheck::HungarianPrefixType
;
1105 if (HungarianPrefixType::HPT_Off
!= Style
.HPType
) {
1106 HungarianPrefix
= HungarianNotation
.getPrefix(D
, HNOption
);
1107 if (!HungarianPrefix
.empty()) {
1108 if (Style
.HPType
== HungarianPrefixType::HPT_LowerCase
)
1109 HungarianPrefix
+= "_";
1111 if (Style
.HPType
== HungarianPrefixType::HPT_CamelCase
)
1112 Fixed
[0] = toupper(Fixed
[0]);
1115 StringRef Mid
= StringRef(Fixed
).trim("_");
1119 return (Style
.Prefix
+ HungarianPrefix
+ Mid
+ Style
.Suffix
).str();
1122 StyleKind
IdentifierNamingCheck::findStyleKind(
1124 ArrayRef
<std::optional
<IdentifierNamingCheck::NamingStyle
>> NamingStyles
,
1125 bool IgnoreMainLikeFunctions
, bool CheckAnonFieldInParentScope
) const {
1126 assert(D
&& D
->getIdentifier() && !D
->getName().empty() && !D
->isImplicit() &&
1127 "Decl must be an explicit identifier with a name.");
1129 if (isa
<ObjCIvarDecl
>(D
) && NamingStyles
[SK_ObjcIvar
])
1132 if (isa
<TypedefDecl
>(D
) && NamingStyles
[SK_Typedef
])
1135 if (isa
<TypeAliasDecl
>(D
) && NamingStyles
[SK_TypeAlias
])
1136 return SK_TypeAlias
;
1138 if (isa
<NamespaceAliasDecl
>(D
) && NamingStyles
[SK_Namespace
])
1139 return SK_Namespace
;
1141 if (const auto *Decl
= dyn_cast
<NamespaceDecl
>(D
)) {
1142 if (Decl
->isAnonymousNamespace())
1145 if (Decl
->isInline() && NamingStyles
[SK_InlineNamespace
])
1146 return SK_InlineNamespace
;
1148 if (NamingStyles
[SK_Namespace
])
1149 return SK_Namespace
;
1152 if (isa
<EnumDecl
>(D
) && NamingStyles
[SK_Enum
])
1155 if (const auto *EnumConst
= dyn_cast
<EnumConstantDecl
>(D
)) {
1156 if (cast
<EnumDecl
>(EnumConst
->getDeclContext())->isScoped() &&
1157 NamingStyles
[SK_ScopedEnumConstant
])
1158 return SK_ScopedEnumConstant
;
1160 if (NamingStyles
[SK_EnumConstant
])
1161 return SK_EnumConstant
;
1163 if (NamingStyles
[SK_Constant
])
1169 if (const auto *Decl
= dyn_cast
<RecordDecl
>(D
)) {
1170 if (Decl
->isAnonymousStructOrUnion())
1173 if (const auto *Definition
= Decl
->getDefinition()) {
1174 if (const auto *CxxRecordDecl
= dyn_cast
<CXXRecordDecl
>(Definition
)) {
1175 if (CxxRecordDecl
->isAbstract() && NamingStyles
[SK_AbstractClass
])
1176 return SK_AbstractClass
;
1179 if (Definition
->isStruct() && NamingStyles
[SK_Struct
])
1182 if (Definition
->isStruct() && NamingStyles
[SK_Class
])
1185 if (Definition
->isClass() && NamingStyles
[SK_Class
])
1188 if (Definition
->isClass() && NamingStyles
[SK_Struct
])
1191 if (Definition
->isUnion() && NamingStyles
[SK_Union
])
1194 if (Definition
->isEnum() && NamingStyles
[SK_Enum
])
1201 if (const auto *Decl
= dyn_cast
<FieldDecl
>(D
)) {
1202 if (CheckAnonFieldInParentScope
) {
1203 const RecordDecl
*Record
= Decl
->getParent();
1204 if (Record
->isAnonymousStructOrUnion()) {
1205 return findStyleKindForAnonField(Decl
, NamingStyles
);
1209 return findStyleKindForField(Decl
, Decl
->getType(), NamingStyles
);
1212 if (const auto *Decl
= dyn_cast
<ParmVarDecl
>(D
)) {
1213 if (isParamInMainLikeFunction(*Decl
, IgnoreMainLikeFunctions
))
1215 QualType Type
= Decl
->getType();
1217 if (Decl
->isConstexpr() && NamingStyles
[SK_ConstexprVariable
])
1218 return SK_ConstexprVariable
;
1220 if (!Type
.isNull() && Type
.isConstQualified()) {
1221 if (Type
.getTypePtr()->isAnyPointerType() &&
1222 NamingStyles
[SK_ConstantPointerParameter
])
1223 return SK_ConstantPointerParameter
;
1225 if (NamingStyles
[SK_ConstantParameter
])
1226 return SK_ConstantParameter
;
1228 if (NamingStyles
[SK_Constant
])
1232 if (Decl
->isParameterPack() && NamingStyles
[SK_ParameterPack
])
1233 return SK_ParameterPack
;
1235 if (!Type
.isNull() && Type
.getTypePtr()->isAnyPointerType() &&
1236 NamingStyles
[SK_PointerParameter
])
1237 return SK_PointerParameter
;
1239 if (NamingStyles
[SK_Parameter
])
1240 return SK_Parameter
;
1245 if (const auto *Decl
= dyn_cast
<VarDecl
>(D
)) {
1246 return findStyleKindForVar(Decl
, Decl
->getType(), NamingStyles
);
1249 if (const auto *Decl
= dyn_cast
<CXXMethodDecl
>(D
)) {
1250 if (Decl
->isMain() || !Decl
->isUserProvided() ||
1251 Decl
->size_overridden_methods() > 0 || Decl
->hasAttr
<OverrideAttr
>())
1254 // If this method has the same name as any base method, this is likely
1255 // necessary even if it's not an override. e.g. CRTP.
1256 for (const CXXBaseSpecifier
&Base
: Decl
->getParent()->bases())
1257 if (const auto *RD
= Base
.getType()->getAsCXXRecordDecl())
1258 if (RD
->hasMemberName(Decl
->getDeclName()))
1261 if (Decl
->isConstexpr() && NamingStyles
[SK_ConstexprMethod
])
1262 return SK_ConstexprMethod
;
1264 if (Decl
->isConstexpr() && NamingStyles
[SK_ConstexprFunction
])
1265 return SK_ConstexprFunction
;
1267 if (Decl
->isStatic() && NamingStyles
[SK_ClassMethod
])
1268 return SK_ClassMethod
;
1270 if (Decl
->isVirtual() && NamingStyles
[SK_VirtualMethod
])
1271 return SK_VirtualMethod
;
1273 if (Decl
->getAccess() == AS_private
&& NamingStyles
[SK_PrivateMethod
])
1274 return SK_PrivateMethod
;
1276 if (Decl
->getAccess() == AS_protected
&& NamingStyles
[SK_ProtectedMethod
])
1277 return SK_ProtectedMethod
;
1279 if (Decl
->getAccess() == AS_public
&& NamingStyles
[SK_PublicMethod
])
1280 return SK_PublicMethod
;
1282 if (NamingStyles
[SK_Method
])
1285 if (NamingStyles
[SK_Function
])
1291 if (const auto *Decl
= dyn_cast
<FunctionDecl
>(D
)) {
1295 if (Decl
->isConstexpr() && NamingStyles
[SK_ConstexprFunction
])
1296 return SK_ConstexprFunction
;
1298 if (Decl
->isGlobal() && NamingStyles
[SK_GlobalFunction
])
1299 return SK_GlobalFunction
;
1301 if (NamingStyles
[SK_Function
])
1305 if (isa
<TemplateTypeParmDecl
>(D
)) {
1306 if (NamingStyles
[SK_TypeTemplateParameter
])
1307 return SK_TypeTemplateParameter
;
1309 if (NamingStyles
[SK_TemplateParameter
])
1310 return SK_TemplateParameter
;
1315 if (isa
<NonTypeTemplateParmDecl
>(D
)) {
1316 if (NamingStyles
[SK_ValueTemplateParameter
])
1317 return SK_ValueTemplateParameter
;
1319 if (NamingStyles
[SK_TemplateParameter
])
1320 return SK_TemplateParameter
;
1325 if (isa
<TemplateTemplateParmDecl
>(D
)) {
1326 if (NamingStyles
[SK_TemplateTemplateParameter
])
1327 return SK_TemplateTemplateParameter
;
1329 if (NamingStyles
[SK_TemplateParameter
])
1330 return SK_TemplateParameter
;
1335 if (isa
<ConceptDecl
>(D
) && NamingStyles
[SK_Concept
])
1341 std::optional
<RenamerClangTidyCheck::FailureInfo
>
1342 IdentifierNamingCheck::getFailureInfo(
1343 StringRef Type
, StringRef Name
, const NamedDecl
*ND
,
1344 SourceLocation Location
,
1345 ArrayRef
<std::optional
<IdentifierNamingCheck::NamingStyle
>> NamingStyles
,
1346 const IdentifierNamingCheck::HungarianNotationOption
&HNOption
,
1347 StyleKind SK
, const SourceManager
&SM
, bool IgnoreFailedSplit
) const {
1348 if (SK
== SK_Invalid
|| !NamingStyles
[SK
])
1349 return std::nullopt
;
1351 const IdentifierNamingCheck::NamingStyle
&Style
= *NamingStyles
[SK
];
1352 if (Style
.IgnoredRegexp
.isValid() && Style
.IgnoredRegexp
.match(Name
))
1353 return std::nullopt
;
1355 if (matchesStyle(Type
, Name
, Style
, HNOption
, ND
))
1356 return std::nullopt
;
1358 std::string KindName
=
1359 fixupWithCase(Type
, StyleNames
[SK
], ND
, Style
, HNOption
,
1360 IdentifierNamingCheck::CT_LowerCase
);
1361 std::replace(KindName
.begin(), KindName
.end(), '_', ' ');
1363 std::string Fixup
= fixupWithStyle(Type
, Name
, Style
, HNOption
, ND
);
1364 if (StringRef(Fixup
) == Name
) {
1365 if (!IgnoreFailedSplit
) {
1366 LLVM_DEBUG(Location
.print(llvm::dbgs(), SM
);
1368 << llvm::formatv(": unable to split words for {0} '{1}'\n",
1371 return std::nullopt
;
1373 return RenamerClangTidyCheck::FailureInfo
{std::move(KindName
),
1377 std::optional
<RenamerClangTidyCheck::FailureInfo
>
1378 IdentifierNamingCheck::getDeclFailureInfo(const NamedDecl
*Decl
,
1379 const SourceManager
&SM
) const {
1380 // Implicit identifiers cannot be renamed.
1381 if (Decl
->isImplicit())
1382 return std::nullopt
;
1384 SourceLocation Loc
= Decl
->getLocation();
1385 const FileStyle
&FileStyle
= getStyleForFile(SM
.getFilename(Loc
));
1386 if (!FileStyle
.isActive())
1387 return std::nullopt
;
1389 return getFailureInfo(
1390 HungarianNotation
.getDeclTypeName(Decl
), Decl
->getName(), Decl
, Loc
,
1391 FileStyle
.getStyles(), FileStyle
.getHNOption(),
1392 findStyleKind(Decl
, FileStyle
.getStyles(),
1393 FileStyle
.isIgnoringMainLikeFunction(),
1394 FileStyle
.isCheckingAnonFieldInParentScope()),
1395 SM
, IgnoreFailedSplit
);
1398 std::optional
<RenamerClangTidyCheck::FailureInfo
>
1399 IdentifierNamingCheck::getMacroFailureInfo(const Token
&MacroNameTok
,
1400 const SourceManager
&SM
) const {
1401 SourceLocation Loc
= MacroNameTok
.getLocation();
1402 const FileStyle
&Style
= getStyleForFile(SM
.getFilename(Loc
));
1403 if (!Style
.isActive())
1404 return std::nullopt
;
1406 return getFailureInfo("", MacroNameTok
.getIdentifierInfo()->getName(),
1407 nullptr, Loc
, Style
.getStyles(), Style
.getHNOption(),
1408 SK_MacroDefinition
, SM
, IgnoreFailedSplit
);
1411 RenamerClangTidyCheck::DiagInfo
1412 IdentifierNamingCheck::getDiagInfo(const NamingCheckId
&ID
,
1413 const NamingCheckFailure
&Failure
) const {
1414 return DiagInfo
{"invalid case style for %0 '%1'",
1415 [&](DiagnosticBuilder
&Diag
) {
1416 Diag
<< Failure
.Info
.KindName
<< ID
.second
;
1420 StringRef
IdentifierNamingCheck::getRealFileName(StringRef FileName
) const {
1421 auto Iter
= RealFileNameCache
.try_emplace(FileName
);
1422 SmallString
<256U> &RealFileName
= Iter
.first
->getValue();
1424 return RealFileName
;
1425 llvm::sys::fs::real_path(FileName
, RealFileName
);
1426 return RealFileName
;
1429 const IdentifierNamingCheck::FileStyle
&
1430 IdentifierNamingCheck::getStyleForFile(StringRef FileName
) const {
1431 if (!GetConfigPerFile
)
1432 return *MainFileStyle
;
1434 StringRef RealFileName
= getRealFileName(FileName
);
1435 StringRef Parent
= llvm::sys::path::parent_path(RealFileName
);
1436 auto Iter
= NamingStylesCache
.find(Parent
);
1437 if (Iter
!= NamingStylesCache
.end())
1438 return Iter
->getValue();
1440 llvm::StringRef CheckName
= getID();
1441 ClangTidyOptions Options
= Context
->getOptionsForFile(RealFileName
);
1442 if (Options
.Checks
&& GlobList(*Options
.Checks
).contains(CheckName
)) {
1443 auto It
= NamingStylesCache
.try_emplace(
1445 getFileStyleFromOptions({CheckName
, Options
.CheckOptions
, Context
}));
1447 return It
.first
->getValue();
1449 // Default construction gives an empty style.
1450 auto It
= NamingStylesCache
.try_emplace(Parent
);
1452 return It
.first
->getValue();
1455 StyleKind
IdentifierNamingCheck::findStyleKindForAnonField(
1456 const FieldDecl
*AnonField
,
1457 ArrayRef
<std::optional
<NamingStyle
>> NamingStyles
) const {
1458 const IndirectFieldDecl
*IFD
=
1459 utils::findOutermostIndirectFieldDeclForField(AnonField
);
1460 assert(IFD
&& "Found an anonymous record field without an IndirectFieldDecl");
1462 QualType Type
= AnonField
->getType();
1464 if (const auto *F
= dyn_cast
<FieldDecl
>(IFD
->chain().front())) {
1465 return findStyleKindForField(F
, Type
, NamingStyles
);
1468 if (const auto *V
= IFD
->getVarDecl()) {
1469 return findStyleKindForVar(V
, Type
, NamingStyles
);
1475 StyleKind
IdentifierNamingCheck::findStyleKindForField(
1476 const FieldDecl
*Field
, QualType Type
,
1477 ArrayRef
<std::optional
<NamingStyle
>> NamingStyles
) const {
1478 if (!Type
.isNull() && Type
.isConstQualified()) {
1479 if (NamingStyles
[SK_ConstantMember
])
1480 return SK_ConstantMember
;
1482 if (NamingStyles
[SK_Constant
])
1486 if (Field
->getAccess() == AS_private
&& NamingStyles
[SK_PrivateMember
])
1487 return SK_PrivateMember
;
1489 if (Field
->getAccess() == AS_protected
&& NamingStyles
[SK_ProtectedMember
])
1490 return SK_ProtectedMember
;
1492 if (Field
->getAccess() == AS_public
&& NamingStyles
[SK_PublicMember
])
1493 return SK_PublicMember
;
1495 if (NamingStyles
[SK_Member
])
1501 StyleKind
IdentifierNamingCheck::findStyleKindForVar(
1502 const VarDecl
*Var
, QualType Type
,
1503 ArrayRef
<std::optional
<NamingStyle
>> NamingStyles
) const {
1504 if (Var
->isConstexpr() && NamingStyles
[SK_ConstexprVariable
])
1505 return SK_ConstexprVariable
;
1507 if (!Type
.isNull() && Type
.isConstQualified()) {
1508 if (Var
->isStaticDataMember() && NamingStyles
[SK_ClassConstant
])
1509 return SK_ClassConstant
;
1511 if (Var
->isFileVarDecl() && Type
.getTypePtr()->isAnyPointerType() &&
1512 NamingStyles
[SK_GlobalConstantPointer
])
1513 return SK_GlobalConstantPointer
;
1515 if (Var
->isFileVarDecl() && NamingStyles
[SK_GlobalConstant
])
1516 return SK_GlobalConstant
;
1518 if (Var
->isStaticLocal() && NamingStyles
[SK_StaticConstant
])
1519 return SK_StaticConstant
;
1521 if (Var
->isLocalVarDecl() && Type
.getTypePtr()->isAnyPointerType() &&
1522 NamingStyles
[SK_LocalConstantPointer
])
1523 return SK_LocalConstantPointer
;
1525 if (Var
->isLocalVarDecl() && NamingStyles
[SK_LocalConstant
])
1526 return SK_LocalConstant
;
1528 if (Var
->isFunctionOrMethodVarDecl() && NamingStyles
[SK_LocalConstant
])
1529 return SK_LocalConstant
;
1531 if (NamingStyles
[SK_Constant
])
1535 if (Var
->isStaticDataMember() && NamingStyles
[SK_ClassMember
])
1536 return SK_ClassMember
;
1538 if (Var
->isFileVarDecl() && Type
.getTypePtr()->isAnyPointerType() &&
1539 NamingStyles
[SK_GlobalPointer
])
1540 return SK_GlobalPointer
;
1542 if (Var
->isFileVarDecl() && NamingStyles
[SK_GlobalVariable
])
1543 return SK_GlobalVariable
;
1545 if (Var
->isStaticLocal() && NamingStyles
[SK_StaticVariable
])
1546 return SK_StaticVariable
;
1548 if (Var
->isLocalVarDecl() && Type
.getTypePtr()->isAnyPointerType() &&
1549 NamingStyles
[SK_LocalPointer
])
1550 return SK_LocalPointer
;
1552 if (Var
->isLocalVarDecl() && NamingStyles
[SK_LocalVariable
])
1553 return SK_LocalVariable
;
1555 if (Var
->isFunctionOrMethodVarDecl() && NamingStyles
[SK_LocalVariable
])
1556 return SK_LocalVariable
;
1558 if (NamingStyles
[SK_Variable
])
1564 } // namespace readability
1565 } // namespace clang::tidy