xref: /llvm-project/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp (revision c79e5acfe8d4bb01d5ae7297dcb900ad8c39c580)
1 //===--- IdentifierNamingCheck.cpp - clang-tidy ---------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "IdentifierNamingCheck.h"
10 
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"
25 #include <optional>
26 
27 #define DEBUG_TYPE "clang-tidy"
28 
29 // FixItHint
30 
31 using namespace clang::ast_matchers;
32 
33 namespace clang::tidy {
34 
35 llvm::ArrayRef<
36     std::pair<readability::IdentifierNamingCheck::CaseType, StringRef>>
37 OptionEnumMapping<
38     readability::IdentifierNamingCheck::CaseType>::getEnumMapping() {
39   static constexpr std::pair<readability::IdentifierNamingCheck::CaseType,
40                              StringRef>
41       Mapping[] = {
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,
48            "Camel_Snake_Case"},
49           {readability::IdentifierNamingCheck::CT_CamelSnakeBack,
50            "camel_Snake_Back"},
51           {readability::IdentifierNamingCheck::CT_LeadingUpperSnakeCase,
52            "Leading_upper_snake_case"}};
53   return {Mapping};
54 }
55 
56 template <>
57 struct OptionEnumMapping<
58     readability::IdentifierNamingCheck::HungarianPrefixType> {
59   using HungarianPrefixType =
60       readability::IdentifierNamingCheck::HungarianPrefixType;
61   static llvm::ArrayRef<std::pair<HungarianPrefixType, StringRef>>
62   getEnumMapping() {
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"}};
68     return {Mapping};
69   }
70 };
71 
72 namespace readability {
73 
74 // clang-format off
75 #define NAMING_KEYS(m) \
76     m(Namespace) \
77     m(InlineNamespace) \
78     m(EnumConstant) \
79     m(ScopedEnumConstant) \
80     m(ConstexprVariable) \
81     m(ConstantMember) \
82     m(PrivateMember) \
83     m(ProtectedMember) \
84     m(PublicMember) \
85     m(Member) \
86     m(ClassConstant) \
87     m(ClassMember) \
88     m(GlobalConstant) \
89     m(GlobalConstantPointer) \
90     m(GlobalPointer) \
91     m(GlobalVariable) \
92     m(LocalConstant) \
93     m(LocalConstantPointer) \
94     m(LocalPointer) \
95     m(LocalVariable) \
96     m(StaticConstant) \
97     m(StaticVariable) \
98     m(Constant) \
99     m(Variable) \
100     m(ConstantParameter) \
101     m(ParameterPack) \
102     m(Parameter) \
103     m(PointerParameter) \
104     m(ConstantPointerParameter) \
105     m(AbstractClass) \
106     m(Struct) \
107     m(Class) \
108     m(Union) \
109     m(Enum) \
110     m(GlobalFunction) \
111     m(ConstexprFunction) \
112     m(Function) \
113     m(ConstexprMethod) \
114     m(VirtualMethod) \
115     m(ClassMethod) \
116     m(PrivateMethod) \
117     m(ProtectedMethod) \
118     m(PublicMethod) \
119     m(Method) \
120     m(Typedef) \
121     m(TypeTemplateParameter) \
122     m(ValueTemplateParameter) \
123     m(TemplateTemplateParameter) \
124     m(TemplateParameter) \
125     m(TypeAlias) \
126     m(MacroDefinition) \
127     m(ObjcIvar) \
128     m(Concept) \
129 
130 enum StyleKind : int {
131 #define ENUMERATE(v) SK_ ## v,
132   NAMING_KEYS(ENUMERATE)
133 #undef ENUMERATE
134   SK_Count,
135   SK_Invalid
136 };
137 
138 static StringRef const StyleNames[] = {
139 #define STRINGIZE(v) #v,
140   NAMING_KEYS(STRINGIZE)
141 #undef STRINGIZE
142 };
143 
144 #define HUNGARIAN_NOTATION_PRIMITIVE_TYPES(m) \
145      m(int8_t) \
146      m(int16_t) \
147      m(int32_t) \
148      m(int64_t) \
149      m(uint8_t) \
150      m(uint16_t) \
151      m(uint32_t) \
152      m(uint64_t) \
153      m(char8_t) \
154      m(char16_t) \
155      m(char32_t) \
156      m(float) \
157      m(double) \
158      m(char) \
159      m(bool) \
160      m(_Bool) \
161      m(int) \
162      m(size_t) \
163      m(wchar_t) \
164      m(short-int) \
165      m(short) \
166      m(signed-int) \
167      m(signed-short) \
168      m(signed-short-int) \
169      m(signed-long-long-int) \
170      m(signed-long-long) \
171      m(signed-long-int) \
172      m(signed-long) \
173      m(signed) \
174      m(unsigned-long-long-int) \
175      m(unsigned-long-long) \
176      m(unsigned-long-int) \
177      m(unsigned-long) \
178      m(unsigned-short-int) \
179      m(unsigned-short) \
180      m(unsigned-int) \
181      m(unsigned-char) \
182      m(unsigned) \
183      m(long-long-int) \
184      m(long-double) \
185      m(long-long) \
186      m(long-int) \
187      m(long) \
188      m(ptrdiff_t) \
189      m(void) \
190 
191 static StringRef const HungarainNotationPrimitiveTypes[] = {
192 #define STRINGIZE(v) #v,
193   HUNGARIAN_NOTATION_PRIMITIVE_TYPES(STRINGIZE)
194 #undef STRINGIZE
195 };
196 
197 #define HUNGARIAN_NOTATION_USER_DEFINED_TYPES(m) \
198      m(BOOL) \
199      m(BOOLEAN) \
200      m(BYTE) \
201      m(CHAR) \
202      m(UCHAR) \
203      m(SHORT) \
204      m(USHORT) \
205      m(WORD) \
206      m(DWORD) \
207      m(DWORD32) \
208      m(DWORD64) \
209      m(LONG) \
210      m(ULONG) \
211      m(ULONG32) \
212      m(ULONG64) \
213      m(ULONGLONG) \
214      m(HANDLE) \
215      m(INT) \
216      m(INT8) \
217      m(INT16) \
218      m(INT32) \
219      m(INT64) \
220      m(UINT) \
221      m(UINT8) \
222      m(UINT16) \
223      m(UINT32) \
224      m(UINT64) \
225      m(PVOID) \
226 
227 static StringRef const HungarainNotationUserDefinedTypes[] = {
228 #define STRINGIZE(v) #v,
229   HUNGARIAN_NOTATION_USER_DEFINED_TYPES(STRINGIZE)
230 #undef STRINGIZE
231 };
232 
233 
234 #undef NAMING_KEYS
235 // clang-format on
236 
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()) {
243     IgnoredRegexp =
244         llvm::Regex(llvm::SmallString<128>({"^", IgnoredRegexpStr, "$"}));
245     if (!IgnoredRegexp.isValid())
246       llvm::errs() << "Invalid IgnoredRegexp regular expression: "
247                    << IgnoredRegexpStr;
248   }
249 }
250 
251 IdentifierNamingCheck::FileStyle IdentifierNamingCheck::getFileStyleFromOptions(
252     const ClangTidyCheck::OptionsView &Options) const {
253   IdentifierNamingCheck::HungarianNotationOption HNOption;
254 
255   HungarianNotation.loadDefaultConfig(HNOption);
256   HungarianNotation.loadFileConfig(Options, HNOption);
257 
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"});
264 
265     auto HPTOpt =
266         Options.get<IdentifierNamingCheck::HungarianPrefixType>(StyleString);
267     if (HPTOpt && !HungarianNotation.checkOptionValid(I))
268       configurationDiag("invalid identifier naming option '%0'") << StyleString;
269 
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);
283 
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));
288   }
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};
293 }
294 
295 std::string IdentifierNamingCheck::HungarianNotation::getDeclTypeName(
296     const NamedDecl *ND) const {
297   const auto *VD = dyn_cast<ValueDecl>(ND);
298   if (!VD)
299     return {};
300 
301   if (isa<FunctionDecl, EnumConstantDecl>(ND))
302     return {};
303 
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;
309 
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');
315   if (!EOL)
316     EOL = Begin + strlen(Begin);
317 
318   const char *PosList[] = {strchr(Begin, '='), strchr(Begin, ';'),
319                            strchr(Begin, ','), strchr(Begin, ')'), EOL};
320   for (const auto &Pos : PosList) {
321     if (Pos > Begin)
322       EOL = std::min(EOL, Pos);
323   }
324 
325   StrLen = EOL - Begin;
326   std::string TypeName;
327   if (StrLen > 0) {
328     std::string Type(Begin, StrLen);
329 
330     static constexpr StringRef Keywords[] = {
331         // Constexpr specifiers
332         "constexpr", "constinit", "consteval",
333         // Qualifier
334         "const", "volatile", "restrict", "mutable",
335         // Storage class specifiers
336         "register", "static", "extern", "thread_local",
337         // Other keywords
338         "virtual"};
339 
340     // Remove keywords
341     for (StringRef Kw : Keywords) {
342       for (size_t Pos = 0;
343            (Pos = Type.find(Kw.data(), Pos)) != std::string::npos;) {
344         Type.replace(Pos, Kw.size(), "");
345       }
346     }
347     TypeName = Type.erase(0, Type.find_first_not_of(' '));
348 
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);
353     }
354 
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("  "), " ");
359     }
360 
361     // Replace " &" with "&".
362     for (size_t Pos = 0; (Pos = Type.find(" &", Pos)) != std::string::npos;
363          Pos += strlen("&")) {
364       Type.replace(Pos, strlen(" &"), "&");
365     }
366 
367     // Replace " *" with "* ".
368     for (size_t Pos = 0; (Pos = Type.find(" *", Pos)) != std::string::npos;
369          Pos += strlen("*")) {
370       Type.replace(Pos, strlen(" *"), "* ");
371     }
372 
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;
383         break;
384       }
385     }
386 
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);
392     }
393 
394     TypeName = Type.erase(0, Type.find_first_not_of(' '));
395 
396     QualType QT = VD->getType();
397     if (!QT.isNull() && QT->isArrayType())
398       TypeName.append("[]");
399   }
400 
401   return TypeName;
402 }
403 
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)) {
409 
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
415   // move.
416   MainFileStyle = &IterAndInserted.first->getValue();
417 }
418 
419 IdentifierNamingCheck::~IdentifierNamingCheck() = default;
420 
421 bool IdentifierNamingCheck::HungarianNotation::checkOptionValid(
422     int StyleKindIndex) const {
423   if ((StyleKindIndex >= SK_EnumConstant) &&
424       (StyleKindIndex <= SK_ConstantParameter))
425     return true;
426 
427   if ((StyleKindIndex >= SK_Parameter) && (StyleKindIndex <= SK_Enum))
428     return true;
429 
430   return false;
431 }
432 
433 bool IdentifierNamingCheck::HungarianNotation::isOptionEnabled(
434     StringRef OptionKey, const llvm::StringMap<std::string> &StrMap) const {
435   if (OptionKey.empty())
436     return false;
437 
438   auto Iter = StrMap.find(OptionKey);
439   if (Iter == StrMap.end())
440     return false;
441 
442   return *llvm::yaml::parseBool(Iter->getValue());
443 }
444 
445 void IdentifierNamingCheck::HungarianNotation::loadFileConfig(
446     const ClangTidyCheck::OptionsView &Options,
447     IdentifierNamingCheck::HungarianNotationOption &HNOption) const {
448 
449   static constexpr StringRef HNOpts[] = {"TreatStructAsClass"};
450   static constexpr StringRef HNDerivedTypes[] = {"Array", "Pointer",
451                                                  "FunctionPointer"};
452 
453   StringRef Section = "HungarianNotation.";
454 
455   SmallString<128> Buffer = {Section, "General."};
456   size_t DefSize = Buffer.size();
457   for (const auto &Opt : HNOpts) {
458     Buffer.truncate(DefSize);
459     Buffer.append(Opt);
460     StringRef Val = Options.get(Buffer, "");
461     if (!Val.empty())
462       HNOption.General[Opt] = Val.str();
463   }
464 
465   Buffer = {Section, "DerivedType."};
466   DefSize = Buffer.size();
467   for (const auto &Type : HNDerivedTypes) {
468     Buffer.truncate(DefSize);
469     Buffer.append(Type);
470     StringRef Val = Options.get(Buffer, "");
471     if (!Val.empty())
472       HNOption.DerivedType[Type] = Val.str();
473   }
474 
475   static constexpr std::pair<StringRef, StringRef> HNCStrings[] = {
476       {"CharPointer", "char*"},
477       {"CharArray", "char[]"},
478       {"WideCharPointer", "wchar_t*"},
479       {"WideCharArray", "wchar_t[]"}};
480 
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, "");
487     if (!Val.empty())
488       HNOption.CString[CStr.second] = Val.str();
489   }
490 
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, "");
497     if (!Val.empty()) {
498       std::string Type = PrimType.str();
499       std::replace(Type.begin(), Type.end(), '-', ' ');
500       HNOption.PrimitiveType[Type] = Val.str();
501     }
502   }
503 
504   Buffer = {Section, "UserDefinedType."};
505   DefSize = Buffer.size();
506   for (const auto &Type : HungarainNotationUserDefinedTypes) {
507     Buffer.truncate(DefSize);
508     Buffer.append(Type);
509     StringRef Val = Options.get(Buffer, "");
510     if (!Val.empty())
511       HNOption.UserDefinedType[Type] = Val.str();
512   }
513 }
514 
515 std::string IdentifierNamingCheck::HungarianNotation::getPrefix(
516     const Decl *D,
517     const IdentifierNamingCheck::HungarianNotationOption &HNOption) const {
518   if (!D)
519     return {};
520   const auto *ND = dyn_cast<NamedDecl>(D);
521   if (!ND)
522     return {};
523 
524   std::string Prefix;
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);
533   }
534 
535   return Prefix;
536 }
537 
538 bool IdentifierNamingCheck::HungarianNotation::removeDuplicatedPrefix(
539     SmallVector<StringRef, 8> &Words,
540     const IdentifierNamingCheck::HungarianNotationOption &HNOption) const {
541   if (Words.size() <= 1)
542     return true;
543 
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};
548 
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);
553         return true;
554       }
555     }
556   }
557 
558   return false;
559 }
560 
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();
566 
567   std::string ModifiedTypeName(TypeName);
568 
569   // Derived types
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());
582           break;
583         }
584       }
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();
590           break;
591         }
592       }
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);
599     }
600   }
601 
602   // Pointers
603   size_t PtrCount = getAsteriskCount(ModifiedTypeName);
604   if (PtrCount > 0) {
605     ModifiedTypeName = [&](std::string Str, StringRef From, StringRef To) {
606       size_t StartPos = 0;
607       while ((StartPos = Str.find(From.data(), StartPos)) !=
608              std::string::npos) {
609         Str.replace(StartPos, From.size(), To.data());
610         StartPos += To.size();
611       }
612       return Str;
613     }(ModifiedTypeName, "*", "");
614   }
615 
616   // Primitive types
617   if (PrefixStr.empty()) {
618     for (const auto &Type : HNOption.PrimitiveType) {
619       if (ModifiedTypeName == Type.getKey()) {
620         PrefixStr = Type.getValue();
621         break;
622       }
623     }
624   }
625 
626   // User-Defined types
627   if (PrefixStr.empty()) {
628     for (const auto &Type : HNOption.UserDefinedType) {
629       if (ModifiedTypeName == Type.getKey()) {
630         PrefixStr = Type.getValue();
631         break;
632       }
633     }
634   }
635 
636   for (size_t Idx = 0; Idx < PtrCount; Idx++)
637     PrefixStr.insert(0, HNOption.DerivedType.lookup("Pointer"));
638 
639   return PrefixStr;
640 }
641 
642 std::string IdentifierNamingCheck::HungarianNotation::getClassPrefix(
643     const CXXRecordDecl *CRD,
644     const IdentifierNamingCheck::HungarianNotationOption &HNOption) const {
645 
646   if (CRD->isUnion())
647     return {};
648 
649   if (CRD->isStruct() &&
650       !isOptionEnabled("TreatStructAsClass", HNOption.General))
651     return {};
652 
653   return CRD->isAbstract() ? "I" : "C";
654 }
655 
656 std::string IdentifierNamingCheck::HungarianNotation::getEnumPrefix(
657     const EnumConstantDecl *ECD) const {
658   const auto *ED = cast<EnumDecl>(ECD->getDeclContext());
659 
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(' '));
664   }
665 
666   static llvm::Regex Splitter(
667       "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
668 
669   StringRef EnumName(Name);
670   SmallVector<StringRef, 8> Substrs;
671   EnumName.split(Substrs, "_", -1, false);
672 
673   SmallVector<StringRef, 8> Words;
674   SmallVector<StringRef, 8> Groups;
675   for (auto Substr : Substrs) {
676     while (!Substr.empty()) {
677       Groups.clear();
678       if (!Splitter.match(Substr, &Groups))
679         break;
680 
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());
690       }
691     }
692   }
693 
694   std::string Initial;
695   for (StringRef Word : Words)
696     Initial += tolower(Word[0]);
697 
698   return Initial;
699 }
700 
701 size_t IdentifierNamingCheck::HungarianNotation::getAsteriskCount(
702     const std::string &TypeName) const {
703   size_t Pos = TypeName.find('*');
704   size_t Count = 0;
705   for (; Pos < TypeName.length(); Pos++, Count++) {
706     if ('*' != TypeName[Pos])
707       break;
708   }
709   return Count;
710 }
711 
712 size_t IdentifierNamingCheck::HungarianNotation::getAsteriskCount(
713     const std::string &TypeName, const NamedDecl *ND) const {
714   size_t PtrCount = 0;
715   if (const auto *TD = dyn_cast<ValueDecl>(ND)) {
716     QualType QT = TD->getType();
717     if (QT->isPointerType())
718       PtrCount = getAsteriskCount(TypeName);
719   }
720   return PtrCount;
721 }
722 
723 void IdentifierNamingCheck::HungarianNotation::loadDefaultConfig(
724     IdentifierNamingCheck::HungarianNotationOption &HNOption) const {
725 
726   // Options
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);
731 
732   // Derived types
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);
737 
738   // C strings
739   static constexpr std::pair<StringRef, StringRef> CStrings[] = {
740       {"char*", "sz"},
741       {"char[]", "sz"},
742       {"wchar_t*", "wsz"},
743       {"wchar_t[]", "wsz"}};
744   for (const auto &CStr : CStrings)
745     HNOption.CString.try_emplace(CStr.first, CStr.second);
746 
747   // clang-format off
748   static constexpr std::pair<StringRef, StringRef> PrimitiveTypes[] = {
749         {"int8_t",                  "i8"  },
750         {"int16_t",                 "i16" },
751         {"int32_t",                 "i32" },
752         {"int64_t",                 "i64" },
753         {"uint8_t",                 "u8"  },
754         {"uint16_t",                "u16" },
755         {"uint32_t",                "u32" },
756         {"uint64_t",                "u64" },
757         {"char8_t",                 "c8"  },
758         {"char16_t",                "c16" },
759         {"char32_t",                "c32" },
760         {"float",                   "f"   },
761         {"double",                  "d"   },
762         {"char",                    "c"   },
763         {"bool",                    "b"   },
764         {"_Bool",                   "b"   },
765         {"int",                     "i"   },
766         {"size_t",                  "n"   },
767         {"wchar_t",                 "wc"  },
768         {"short int",               "si"  },
769         {"short",                   "s"   },
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"  },
777         {"signed",                  "s"   },
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"  },
786         {"unsigned",                "u"   },
787         {"long long int",           "lli" },
788         {"long double",             "ld"  },
789         {"long long",               "ll"  },
790         {"long int",                "li"  },
791         {"long",                    "l"   },
792         {"ptrdiff_t",               "p"   },
793         {"void",                    ""    }};
794   // clang-format on
795   for (const auto &PT : PrimitiveTypes)
796     HNOption.PrimitiveType.try_emplace(PT.first, PT.second);
797 
798   // clang-format off
799   static constexpr std::pair<StringRef, StringRef> UserDefinedTypes[] = {
800       // Windows data types
801       {"BOOL",                    "b"   },
802       {"BOOLEAN",                 "b"   },
803       {"BYTE",                    "by"  },
804       {"CHAR",                    "c"   },
805       {"UCHAR",                   "uc"  },
806       {"SHORT",                   "s"   },
807       {"USHORT",                  "us"  },
808       {"WORD",                    "w"   },
809       {"DWORD",                   "dw"  },
810       {"DWORD32",                 "dw32"},
811       {"DWORD64",                 "dw64"},
812       {"LONG",                    "l"   },
813       {"ULONG",                   "ul"  },
814       {"ULONG32",                 "ul32"},
815       {"ULONG64",                 "ul64"},
816       {"ULONGLONG",               "ull" },
817       {"HANDLE",                  "h"   },
818       {"INT",                     "i"   },
819       {"INT8",                    "i8"  },
820       {"INT16",                   "i16" },
821       {"INT32",                   "i32" },
822       {"INT64",                   "i64" },
823       {"UINT",                    "ui"  },
824       {"UINT8",                   "u8"  },
825       {"UINT16",                  "u16" },
826       {"UINT32",                  "u32" },
827       {"UINT64",                  "u64" },
828       {"PVOID",                   "p"   } };
829   // clang-format on
830   for (const auto &UDT : UserDefinedTypes)
831     HNOption.UserDefinedType.try_emplace(UDT.first, UDT.second);
832 }
833 
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) {
839     if (!Styles[I])
840       continue;
841     size_t StyleSize = StyleNames[I].size();
842     StyleString.assign({StyleNames[I], "HungarianPrefix"});
843 
844     Options.store(Opts, StyleString, Styles[I]->HPType);
845 
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);
859     }
860   }
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());
867 }
868 
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[] = {
875       llvm::Regex("^.*$"),
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])*$"),
883   };
884 
885   if (!Name.consume_front(Style.Prefix))
886     return false;
887   if (!Name.consume_back(Style.Suffix))
888     return false;
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))
893         return false;
894       if (Style.HPType ==
895               IdentifierNamingCheck::HungarianPrefixType::HPT_LowerCase &&
896           !Name.consume_front("_"))
897         return false;
898     }
899   }
900 
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("_"))
904     return false;
905 
906   if (Style.Case && !Matchers[static_cast<size_t>(*Style.Case)].match(Name))
907     return false;
908 
909   return true;
910 }
911 
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]|$)");
919 
920   SmallVector<StringRef, 8> Substrs;
921   Name.split(Substrs, "_", -1, false);
922 
923   SmallVector<StringRef, 8> Words;
924   SmallVector<StringRef, 8> Groups;
925   for (auto Substr : Substrs) {
926     while (!Substr.empty()) {
927       Groups.clear();
928       if (!Splitter.match(Substr, &Groups))
929         break;
930 
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());
940       }
941     }
942   }
943 
944   if (Words.empty())
945     return Name.str();
946 
947   if (IdentifierNamingCheck::HungarianPrefixType::HPT_Off != Style.HPType) {
948     HungarianNotation.removeDuplicatedPrefix(Words, HNOption);
949   }
950 
951   SmallString<128> Fixup;
952   switch (Case) {
953   case IdentifierNamingCheck::CT_AnyCase:
954     return Name.str();
955     break;
956 
957   case IdentifierNamingCheck::CT_LowerCase:
958     for (auto const &Word : Words) {
959       if (&Word != &Words.front())
960         Fixup += "_";
961       Fixup += Word.lower();
962     }
963     break;
964 
965   case IdentifierNamingCheck::CT_UpperCase:
966     for (auto const &Word : Words) {
967       if (&Word != &Words.front())
968         Fixup += "_";
969       Fixup += Word.upper();
970     }
971     break;
972 
973   case IdentifierNamingCheck::CT_CamelCase:
974     for (auto const &Word : Words) {
975       Fixup += toupper(Word.front());
976       Fixup += Word.substr(1).lower();
977     }
978     break;
979 
980   case IdentifierNamingCheck::CT_CamelBack:
981     for (auto const &Word : Words) {
982       if (&Word == &Words.front()) {
983         Fixup += Word.lower();
984       } else {
985         Fixup += toupper(Word.front());
986         Fixup += Word.substr(1).lower();
987       }
988     }
989     break;
990 
991   case IdentifierNamingCheck::CT_CamelSnakeCase:
992     for (auto const &Word : Words) {
993       if (&Word != &Words.front())
994         Fixup += "_";
995       Fixup += toupper(Word.front());
996       Fixup += Word.substr(1).lower();
997     }
998     break;
999 
1000   case IdentifierNamingCheck::CT_CamelSnakeBack:
1001     for (auto const &Word : Words) {
1002       if (&Word != &Words.front()) {
1003         Fixup += "_";
1004         Fixup += toupper(Word.front());
1005       } else {
1006         Fixup += tolower(Word.front());
1007       }
1008       Fixup += Word.substr(1).lower();
1009     }
1010     break;
1011 
1012   case IdentifierNamingCheck::CT_LeadingUpperSnakeCase:
1013     for (auto const &Word : Words) {
1014       if (&Word != &Words.front()) {
1015         Fixup += "_";
1016         Fixup += Word.lower();
1017       } else {
1018         Fixup += toupper(Word.front());
1019         Fixup += Word.substr(1).lower();
1020       }
1021     }
1022     break;
1023   }
1024 
1025   return Fixup.str().str();
1026 }
1027 
1028 bool IdentifierNamingCheck::isParamInMainLikeFunction(
1029     const ParmVarDecl &ParmDecl, bool IncludeMainLike) const {
1030   const auto *FDecl =
1031       dyn_cast_or_null<FunctionDecl>(ParmDecl.getParentFunctionOrMethod());
1032   if (!FDecl)
1033     return false;
1034   if (FDecl->isMain())
1035     return true;
1036   if (!IncludeMainLike)
1037     return false;
1038   if (FDecl->getAccess() != AS_public && FDecl->getAccess() != AS_none)
1039     return false;
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())
1043     return false;
1044   enum MainType { None, Main, WMain };
1045   auto IsCharPtrPtr = [](QualType QType) -> MainType {
1046     if (QType.isNull())
1047       return None;
1048     if (QType = QType->getPointeeType(), QType.isNull())
1049       return None;
1050     if (QType = QType->getPointeeType(), QType.isNull())
1051       return None;
1052     if (QType->isCharType())
1053       return Main;
1054     if (QType->isWideCharType())
1055       return WMain;
1056     return None;
1057   };
1058   auto IsIntType = [](QualType QType) {
1059     if (QType.isNull())
1060       return false;
1061     if (const auto *Builtin =
1062             dyn_cast<BuiltinType>(QType->getUnqualifiedDesugaredType())) {
1063       return Builtin->getKind() == BuiltinType::Int;
1064     }
1065     return false;
1066   };
1067   if (!IsIntType(FDecl->getReturnType()))
1068     return false;
1069   if (FDecl->getNumParams() < 2 || FDecl->getNumParams() > 3)
1070     return false;
1071   if (!IsIntType(FDecl->parameters()[0]->getType()))
1072     return false;
1073   MainType Type = IsCharPtrPtr(FDecl->parameters()[1]->getType());
1074   if (Type == None)
1075     return false;
1076   if (FDecl->getNumParams() == 3 &&
1077       IsCharPtrPtr(FDecl->parameters()[2]->getType()) != Type)
1078     return false;
1079 
1080   if (Type == Main) {
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());
1085   }
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());
1090 }
1091 
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));
1102 
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 += "_";
1110 
1111       if (Style.HPType == HungarianPrefixType::HPT_CamelCase)
1112         Fixed[0] = toupper(Fixed[0]);
1113     }
1114   }
1115   StringRef Mid = StringRef(Fixed).trim("_");
1116   if (Mid.empty())
1117     Mid = "_";
1118 
1119   return (Style.Prefix + HungarianPrefix + Mid + Style.Suffix).str();
1120 }
1121 
1122 StyleKind IdentifierNamingCheck::findStyleKind(
1123     const NamedDecl *D,
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.");
1128 
1129   if (isa<ObjCIvarDecl>(D) && NamingStyles[SK_ObjcIvar])
1130     return SK_ObjcIvar;
1131 
1132   if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef])
1133     return SK_Typedef;
1134 
1135   if (isa<TypeAliasDecl>(D) && NamingStyles[SK_TypeAlias])
1136     return SK_TypeAlias;
1137 
1138   if (isa<NamespaceAliasDecl>(D) && NamingStyles[SK_Namespace])
1139     return SK_Namespace;
1140 
1141   if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) {
1142     if (Decl->isAnonymousNamespace())
1143       return SK_Invalid;
1144 
1145     if (Decl->isInline() && NamingStyles[SK_InlineNamespace])
1146       return SK_InlineNamespace;
1147 
1148     if (NamingStyles[SK_Namespace])
1149       return SK_Namespace;
1150   }
1151 
1152   if (isa<EnumDecl>(D) && NamingStyles[SK_Enum])
1153     return SK_Enum;
1154 
1155   if (const auto *EnumConst = dyn_cast<EnumConstantDecl>(D)) {
1156     if (cast<EnumDecl>(EnumConst->getDeclContext())->isScoped() &&
1157         NamingStyles[SK_ScopedEnumConstant])
1158       return SK_ScopedEnumConstant;
1159 
1160     if (NamingStyles[SK_EnumConstant])
1161       return SK_EnumConstant;
1162 
1163     if (NamingStyles[SK_Constant])
1164       return SK_Constant;
1165 
1166     return SK_Invalid;
1167   }
1168 
1169   if (const auto *Decl = dyn_cast<RecordDecl>(D)) {
1170     if (Decl->isAnonymousStructOrUnion())
1171       return SK_Invalid;
1172 
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;
1177       }
1178 
1179       if (Definition->isStruct() && NamingStyles[SK_Struct])
1180         return SK_Struct;
1181 
1182       if (Definition->isStruct() && NamingStyles[SK_Class])
1183         return SK_Class;
1184 
1185       if (Definition->isClass() && NamingStyles[SK_Class])
1186         return SK_Class;
1187 
1188       if (Definition->isClass() && NamingStyles[SK_Struct])
1189         return SK_Struct;
1190 
1191       if (Definition->isUnion() && NamingStyles[SK_Union])
1192         return SK_Union;
1193 
1194       if (Definition->isEnum() && NamingStyles[SK_Enum])
1195         return SK_Enum;
1196     }
1197 
1198     return SK_Invalid;
1199   }
1200 
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);
1206       }
1207     }
1208 
1209     return findStyleKindForField(Decl, Decl->getType(), NamingStyles);
1210   }
1211 
1212   if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {
1213     if (isParamInMainLikeFunction(*Decl, IgnoreMainLikeFunctions))
1214       return SK_Invalid;
1215     QualType Type = Decl->getType();
1216 
1217     if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])
1218       return SK_ConstexprVariable;
1219 
1220     if (!Type.isNull() && Type.isConstQualified()) {
1221       if (Type.getTypePtr()->isAnyPointerType() &&
1222           NamingStyles[SK_ConstantPointerParameter])
1223         return SK_ConstantPointerParameter;
1224 
1225       if (NamingStyles[SK_ConstantParameter])
1226         return SK_ConstantParameter;
1227 
1228       if (NamingStyles[SK_Constant])
1229         return SK_Constant;
1230     }
1231 
1232     if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack])
1233       return SK_ParameterPack;
1234 
1235     if (!Type.isNull() && Type.getTypePtr()->isAnyPointerType() &&
1236         NamingStyles[SK_PointerParameter])
1237       return SK_PointerParameter;
1238 
1239     if (NamingStyles[SK_Parameter])
1240       return SK_Parameter;
1241 
1242     return SK_Invalid;
1243   }
1244 
1245   if (const auto *Decl = dyn_cast<VarDecl>(D)) {
1246     return findStyleKindForVar(Decl, Decl->getType(), NamingStyles);
1247   }
1248 
1249   if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {
1250     if (Decl->isMain() || !Decl->isUserProvided() ||
1251         Decl->size_overridden_methods() > 0 || Decl->hasAttr<OverrideAttr>())
1252       return SK_Invalid;
1253 
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()))
1259           return SK_Invalid;
1260 
1261     if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod])
1262       return SK_ConstexprMethod;
1263 
1264     if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])
1265       return SK_ConstexprFunction;
1266 
1267     if (Decl->isStatic() && NamingStyles[SK_ClassMethod])
1268       return SK_ClassMethod;
1269 
1270     if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod])
1271       return SK_VirtualMethod;
1272 
1273     if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMethod])
1274       return SK_PrivateMethod;
1275 
1276     if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMethod])
1277       return SK_ProtectedMethod;
1278 
1279     if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod])
1280       return SK_PublicMethod;
1281 
1282     if (NamingStyles[SK_Method])
1283       return SK_Method;
1284 
1285     if (NamingStyles[SK_Function])
1286       return SK_Function;
1287 
1288     return SK_Invalid;
1289   }
1290 
1291   if (const auto *Decl = dyn_cast<FunctionDecl>(D)) {
1292     if (Decl->isMain())
1293       return SK_Invalid;
1294 
1295     if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])
1296       return SK_ConstexprFunction;
1297 
1298     if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction])
1299       return SK_GlobalFunction;
1300 
1301     if (NamingStyles[SK_Function])
1302       return SK_Function;
1303   }
1304 
1305   if (isa<TemplateTypeParmDecl>(D)) {
1306     if (NamingStyles[SK_TypeTemplateParameter])
1307       return SK_TypeTemplateParameter;
1308 
1309     if (NamingStyles[SK_TemplateParameter])
1310       return SK_TemplateParameter;
1311 
1312     return SK_Invalid;
1313   }
1314 
1315   if (isa<NonTypeTemplateParmDecl>(D)) {
1316     if (NamingStyles[SK_ValueTemplateParameter])
1317       return SK_ValueTemplateParameter;
1318 
1319     if (NamingStyles[SK_TemplateParameter])
1320       return SK_TemplateParameter;
1321 
1322     return SK_Invalid;
1323   }
1324 
1325   if (isa<TemplateTemplateParmDecl>(D)) {
1326     if (NamingStyles[SK_TemplateTemplateParameter])
1327       return SK_TemplateTemplateParameter;
1328 
1329     if (NamingStyles[SK_TemplateParameter])
1330       return SK_TemplateParameter;
1331 
1332     return SK_Invalid;
1333   }
1334 
1335   if (isa<ConceptDecl>(D) && NamingStyles[SK_Concept])
1336     return SK_Concept;
1337 
1338   return SK_Invalid;
1339 }
1340 
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;
1350 
1351   const IdentifierNamingCheck::NamingStyle &Style = *NamingStyles[SK];
1352   if (Style.IgnoredRegexp.isValid() && Style.IgnoredRegexp.match(Name))
1353     return std::nullopt;
1354 
1355   if (matchesStyle(Type, Name, Style, HNOption, ND))
1356     return std::nullopt;
1357 
1358   std::string KindName =
1359       fixupWithCase(Type, StyleNames[SK], ND, Style, HNOption,
1360                     IdentifierNamingCheck::CT_LowerCase);
1361   std::replace(KindName.begin(), KindName.end(), '_', ' ');
1362 
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);
1367                  llvm::dbgs()
1368                  << llvm::formatv(": unable to split words for {0} '{1}'\n",
1369                                   KindName, Name));
1370     }
1371     return std::nullopt;
1372   }
1373   return RenamerClangTidyCheck::FailureInfo{std::move(KindName),
1374                                             std::move(Fixup)};
1375 }
1376 
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;
1383 
1384   SourceLocation Loc = Decl->getLocation();
1385   const FileStyle &FileStyle = getStyleForFile(SM.getFilename(Loc));
1386   if (!FileStyle.isActive())
1387     return std::nullopt;
1388 
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);
1396 }
1397 
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;
1405 
1406   return getFailureInfo("", MacroNameTok.getIdentifierInfo()->getName(),
1407                         nullptr, Loc, Style.getStyles(), Style.getHNOption(),
1408                         SK_MacroDefinition, SM, IgnoreFailedSplit);
1409 }
1410 
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;
1417                   }};
1418 }
1419 
1420 StringRef IdentifierNamingCheck::getRealFileName(StringRef FileName) const {
1421   auto Iter = RealFileNameCache.try_emplace(FileName);
1422   SmallString<256U> &RealFileName = Iter.first->getValue();
1423   if (!Iter.second)
1424     return RealFileName;
1425   llvm::sys::fs::real_path(FileName, RealFileName);
1426   return RealFileName;
1427 }
1428 
1429 const IdentifierNamingCheck::FileStyle &
1430 IdentifierNamingCheck::getStyleForFile(StringRef FileName) const {
1431   if (!GetConfigPerFile)
1432     return *MainFileStyle;
1433 
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();
1439 
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(
1444         Parent,
1445         getFileStyleFromOptions({CheckName, Options.CheckOptions, Context}));
1446     assert(It.second);
1447     return It.first->getValue();
1448   }
1449   // Default construction gives an empty style.
1450   auto It = NamingStylesCache.try_emplace(Parent);
1451   assert(It.second);
1452   return It.first->getValue();
1453 }
1454 
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");
1461 
1462   QualType Type = AnonField->getType();
1463 
1464   if (const auto *F = dyn_cast<FieldDecl>(IFD->chain().front())) {
1465     return findStyleKindForField(F, Type, NamingStyles);
1466   }
1467 
1468   if (const auto *V = IFD->getVarDecl()) {
1469     return findStyleKindForVar(V, Type, NamingStyles);
1470   }
1471 
1472   return SK_Invalid;
1473 }
1474 
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;
1481 
1482     if (NamingStyles[SK_Constant])
1483       return SK_Constant;
1484   }
1485 
1486   if (Field->getAccess() == AS_private && NamingStyles[SK_PrivateMember])
1487     return SK_PrivateMember;
1488 
1489   if (Field->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember])
1490     return SK_ProtectedMember;
1491 
1492   if (Field->getAccess() == AS_public && NamingStyles[SK_PublicMember])
1493     return SK_PublicMember;
1494 
1495   if (NamingStyles[SK_Member])
1496     return SK_Member;
1497 
1498   return SK_Invalid;
1499 }
1500 
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;
1506 
1507   if (!Type.isNull() && Type.isConstQualified()) {
1508     if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstant])
1509       return SK_ClassConstant;
1510 
1511     if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
1512         NamingStyles[SK_GlobalConstantPointer])
1513       return SK_GlobalConstantPointer;
1514 
1515     if (Var->isFileVarDecl() && NamingStyles[SK_GlobalConstant])
1516       return SK_GlobalConstant;
1517 
1518     if (Var->isStaticLocal() && NamingStyles[SK_StaticConstant])
1519       return SK_StaticConstant;
1520 
1521     if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
1522         NamingStyles[SK_LocalConstantPointer])
1523       return SK_LocalConstantPointer;
1524 
1525     if (Var->isLocalVarDecl() && NamingStyles[SK_LocalConstant])
1526       return SK_LocalConstant;
1527 
1528     if (Var->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant])
1529       return SK_LocalConstant;
1530 
1531     if (NamingStyles[SK_Constant])
1532       return SK_Constant;
1533   }
1534 
1535   if (Var->isStaticDataMember() && NamingStyles[SK_ClassMember])
1536     return SK_ClassMember;
1537 
1538   if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
1539       NamingStyles[SK_GlobalPointer])
1540     return SK_GlobalPointer;
1541 
1542   if (Var->isFileVarDecl() && NamingStyles[SK_GlobalVariable])
1543     return SK_GlobalVariable;
1544 
1545   if (Var->isStaticLocal() && NamingStyles[SK_StaticVariable])
1546     return SK_StaticVariable;
1547 
1548   if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&
1549       NamingStyles[SK_LocalPointer])
1550     return SK_LocalPointer;
1551 
1552   if (Var->isLocalVarDecl() && NamingStyles[SK_LocalVariable])
1553     return SK_LocalVariable;
1554 
1555   if (Var->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable])
1556     return SK_LocalVariable;
1557 
1558   if (NamingStyles[SK_Variable])
1559     return SK_Variable;
1560 
1561   return SK_Invalid;
1562 }
1563 
1564 } // namespace readability
1565 } // namespace clang::tidy
1566