brintos

brintos / llvm-project-archived public Read only

0
0
Text · 49.6 KiB · d1583a6 Raw
1579 lines · cpp
1//===----------------------------------------------------------------------===//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-exception6//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/StringRef.h"18#include "llvm/Support/Debug.h"19#include "llvm/Support/FormatVariadic.h"20#include "llvm/Support/Path.h"21#include "llvm/Support/Regex.h"22#include "llvm/Support/YAMLParser.h"23#include <optional>24 25#define DEBUG_TYPE "clang-tidy"26 27// FixItHint28 29using namespace clang::ast_matchers;30 31namespace clang::tidy {32 33llvm::ArrayRef<34    std::pair<readability::IdentifierNamingCheck::CaseType, StringRef>>35OptionEnumMapping<36    readability::IdentifierNamingCheck::CaseType>::getEnumMapping() {37  static constexpr std::pair<readability::IdentifierNamingCheck::CaseType,38                             StringRef>39      Mapping[] = {40          {readability::IdentifierNamingCheck::CT_AnyCase, "aNy_CasE"},41          {readability::IdentifierNamingCheck::CT_LowerCase, "lower_case"},42          {readability::IdentifierNamingCheck::CT_UpperCase, "UPPER_CASE"},43          {readability::IdentifierNamingCheck::CT_CamelBack, "camelBack"},44          {readability::IdentifierNamingCheck::CT_CamelCase, "CamelCase"},45          {readability::IdentifierNamingCheck::CT_CamelSnakeCase,46           "Camel_Snake_Case"},47          {readability::IdentifierNamingCheck::CT_CamelSnakeBack,48           "camel_Snake_Back"},49          {readability::IdentifierNamingCheck::CT_LeadingUpperSnakeCase,50           "Leading_upper_snake_case"}};51  return {Mapping};52}53 54template <>55struct OptionEnumMapping<56    readability::IdentifierNamingCheck::HungarianPrefixType> {57  using HungarianPrefixType =58      readability::IdentifierNamingCheck::HungarianPrefixType;59  static llvm::ArrayRef<std::pair<HungarianPrefixType, StringRef>>60  getEnumMapping() {61    static constexpr std::pair<HungarianPrefixType, StringRef> Mapping[] = {62        {HungarianPrefixType::HPT_Off, "Off"},63        {HungarianPrefixType::HPT_On, "On"},64        {HungarianPrefixType::HPT_LowerCase, "LowerCase"},65        {HungarianPrefixType::HPT_CamelCase, "CamelCase"}};66    return {Mapping};67  }68};69 70namespace readability {71 72// clang-format off73#define NAMING_KEYS(m) \74    m(Namespace) \75    m(InlineNamespace) \76    m(EnumConstant) \77    m(ScopedEnumConstant) \78    m(ConstexprVariable) \79    m(ConstantMember) \80    m(PrivateMember) \81    m(ProtectedMember) \82    m(PublicMember) \83    m(Member) \84    m(ClassConstant) \85    m(ClassMember) \86    m(ClassConstexpr) \87    m(GlobalConstexprVariable) \88    m(GlobalConstant) \89    m(GlobalConstantPointer) \90    m(GlobalPointer) \91    m(GlobalVariable) \92    m(LocalConstexprVariable) \93    m(LocalConstant) \94    m(LocalConstantPointer) \95    m(LocalPointer) \96    m(LocalVariable) \97    m(StaticConstexprVariable) \98    m(StaticConstant) \99    m(StaticVariable) \100    m(Constant) \101    m(Variable) \102    m(ConstantParameter) \103    m(ParameterPack) \104    m(Parameter) \105    m(PointerParameter) \106    m(ConstantPointerParameter) \107    m(AbstractClass) \108    m(Struct) \109    m(Class) \110    m(Union) \111    m(Enum) \112    m(GlobalFunction) \113    m(ConstexprFunction) \114    m(Function) \115    m(ConstexprMethod) \116    m(VirtualMethod) \117    m(ClassMethod) \118    m(PrivateMethod) \119    m(ProtectedMethod) \120    m(PublicMethod) \121    m(Method) \122    m(Typedef) \123    m(TypeTemplateParameter) \124    m(ValueTemplateParameter) \125    m(TemplateTemplateParameter) \126    m(TemplateParameter) \127    m(TypeAlias) \128    m(MacroDefinition) \129    m(ObjcIvar) \130    m(Concept) \131 132enum StyleKind : int {133#define ENUMERATE(v) SK_ ## v,134  NAMING_KEYS(ENUMERATE)135#undef ENUMERATE136  SK_Count,137  SK_Invalid138};139 140static StringRef const StyleNames[] = {141#define STRINGIZE(v) #v,142  NAMING_KEYS(STRINGIZE)143#undef STRINGIZE144};145 146#define HUNGARIAN_NOTATION_PRIMITIVE_TYPES(m) \147     m(int8_t) \148     m(int16_t) \149     m(int32_t) \150     m(int64_t) \151     m(uint8_t) \152     m(uint16_t) \153     m(uint32_t) \154     m(uint64_t) \155     m(char8_t) \156     m(char16_t) \157     m(char32_t) \158     m(float) \159     m(double) \160     m(char) \161     m(bool) \162     m(_Bool) \163     m(int) \164     m(size_t) \165     m(wchar_t) \166     m(short-int) \167     m(short) \168     m(signed-int) \169     m(signed-short) \170     m(signed-short-int) \171     m(signed-long-long-int) \172     m(signed-long-long) \173     m(signed-long-int) \174     m(signed-long) \175     m(signed) \176     m(unsigned-long-long-int) \177     m(unsigned-long-long) \178     m(unsigned-long-int) \179     m(unsigned-long) \180     m(unsigned-short-int) \181     m(unsigned-short) \182     m(unsigned-int) \183     m(unsigned-char) \184     m(unsigned) \185     m(long-long-int) \186     m(long-double) \187     m(long-long) \188     m(long-int) \189     m(long) \190     m(ptrdiff_t) \191     m(void) \192 193static StringRef const HungarianNotationPrimitiveTypes[] = {194#define STRINGIZE(v) #v,195  HUNGARIAN_NOTATION_PRIMITIVE_TYPES(STRINGIZE)196#undef STRINGIZE197};198 199#define HUNGARIAN_NOTATION_USER_DEFINED_TYPES(m) \200     m(BOOL) \201     m(BOOLEAN) \202     m(BYTE) \203     m(CHAR) \204     m(UCHAR) \205     m(SHORT) \206     m(USHORT) \207     m(WORD) \208     m(DWORD) \209     m(DWORD32) \210     m(DWORD64) \211     m(LONG) \212     m(ULONG) \213     m(ULONG32) \214     m(ULONG64) \215     m(ULONGLONG) \216     m(HANDLE) \217     m(INT) \218     m(INT8) \219     m(INT16) \220     m(INT32) \221     m(INT64) \222     m(UINT) \223     m(UINT8) \224     m(UINT16) \225     m(UINT32) \226     m(UINT64) \227     m(PVOID) \228 229static StringRef const HungarianNotationUserDefinedTypes[] = {230#define STRINGIZE(v) #v,231  HUNGARIAN_NOTATION_USER_DEFINED_TYPES(STRINGIZE)232#undef STRINGIZE233};234 235 236#undef NAMING_KEYS237// clang-format on238 239IdentifierNamingCheck::NamingStyle::NamingStyle(240    std::optional<IdentifierNamingCheck::CaseType> Case, StringRef Prefix,241    StringRef Suffix, StringRef IgnoredRegexpStr, HungarianPrefixType HPType)242    : Case(Case), Prefix(Prefix), Suffix(Suffix),243      IgnoredRegexpStr(IgnoredRegexpStr), HPType(HPType) {244  if (!IgnoredRegexpStr.empty()) {245    IgnoredRegexp =246        llvm::Regex(llvm::SmallString<128>({"^", IgnoredRegexpStr, "$"}));247    if (!IgnoredRegexp.isValid())248      llvm::errs() << "Invalid IgnoredRegexp regular expression: "249                   << IgnoredRegexpStr;250  }251}252 253IdentifierNamingCheck::FileStyle IdentifierNamingCheck::getFileStyleFromOptions(254    const ClangTidyCheck::OptionsView &Options) const {255  IdentifierNamingCheck::HungarianNotationOption HNOption;256 257  HungarianNotation.loadDefaultConfig(HNOption);258  HungarianNotation.loadFileConfig(Options, HNOption);259 260  SmallVector<std::optional<IdentifierNamingCheck::NamingStyle>, 0> Styles;261  Styles.resize(SK_Count);262  SmallString<64> StyleString;263  for (unsigned I = 0; I < SK_Count; ++I) {264    const size_t StyleSize = StyleNames[I].size();265    StyleString.assign({StyleNames[I], "HungarianPrefix"});266 267    auto HPTOpt =268        Options.get<IdentifierNamingCheck::HungarianPrefixType>(StyleString);269    if (HPTOpt && !HungarianNotation.checkOptionValid(I))270      configurationDiag("invalid identifier naming option '%0'") << StyleString;271 272    memcpy(&StyleString[StyleSize], "IgnoredRegexp", 13);273    StyleString.truncate(StyleSize + 13);274    const std::optional<StringRef> IgnoredRegexpStr = Options.get(StyleString);275    memcpy(&StyleString[StyleSize], "Prefix", 6);276    StyleString.truncate(StyleSize + 6);277    const std::optional<StringRef> Prefix(Options.get(StyleString));278    // Fast replacement of [Pre]fix -> [Suf]fix.279    memcpy(&StyleString[StyleSize], "Suf", 3);280    const std::optional<StringRef> Postfix(Options.get(StyleString));281    memcpy(&StyleString[StyleSize], "Case", 4);282    StyleString.pop_back_n(2);283    std::optional<CaseType> CaseOptional =284        Options.get<IdentifierNamingCheck::CaseType>(StyleString);285 286    if (CaseOptional || Prefix || Postfix || IgnoredRegexpStr || HPTOpt)287      Styles[I].emplace(std::move(CaseOptional), Prefix.value_or(""),288                        Postfix.value_or(""), IgnoredRegexpStr.value_or(""),289                        HPTOpt.value_or(IdentifierNamingCheck::HPT_Off));290  }291  const bool IgnoreMainLike = Options.get("IgnoreMainLikeFunctions", false);292  const bool CheckAnonFieldInParent =293      Options.get("CheckAnonFieldInParent", false);294  return {std::move(Styles), std::move(HNOption), IgnoreMainLike,295          CheckAnonFieldInParent};296}297 298std::string IdentifierNamingCheck::HungarianNotation::getDeclTypeName(299    const NamedDecl *ND) const {300  const auto *VD = dyn_cast<ValueDecl>(ND);301  if (!VD)302    return {};303 304  if (isa<FunctionDecl, EnumConstantDecl>(ND))305    return {};306 307  // Get type text of variable declarations.308  auto &SM = VD->getASTContext().getSourceManager();309  const char *Begin = SM.getCharacterData(VD->getBeginLoc());310  const char *End = SM.getCharacterData(VD->getEndLoc());311  intptr_t StrLen = End - Begin;312 313  // FIXME: Sometimes the value that returns from ValDecl->getEndLoc()314  // is wrong(out of location of Decl). This causes `StrLen` will be assigned315  // an unexpected large value. Current workaround to find the terminated316  // character instead of the `getEndLoc()` function.317  const char *EOL = strchr(Begin, '\n');318  if (!EOL)319    EOL = Begin + strlen(Begin);320 321  const char *PosList[] = {strchr(Begin, '='), strchr(Begin, ';'),322                           strchr(Begin, ','), strchr(Begin, ')'), EOL};323  for (const auto &Pos : PosList) {324    if (Pos > Begin)325      EOL = std::min(EOL, Pos);326  }327 328  StrLen = EOL - Begin;329  std::string TypeName;330  if (StrLen > 0) {331    std::string Type(Begin, StrLen);332 333    static constexpr StringRef Keywords[] = {334        // Constexpr specifiers335        "constexpr", "constinit", "consteval",336        // Qualifier337        "const", "volatile", "restrict", "mutable",338        // Storage class specifiers339        "register", "static", "extern", "thread_local",340        // Other keywords341        "virtual"};342 343    // Remove keywords344    for (const StringRef Kw : Keywords) {345      for (size_t Pos = 0; (Pos = Type.find(Kw, Pos)) != std::string::npos;) {346        Type.replace(Pos, Kw.size(), "");347      }348    }349    TypeName = Type.erase(0, Type.find_first_not_of(' '));350 351    // Remove template parameters352    const size_t Pos = Type.find('<');353    if (Pos != std::string::npos) {354      TypeName = Type.erase(Pos, Type.size() - Pos);355    }356 357    // Replace spaces with single space.358    for (size_t Pos = 0; (Pos = Type.find("  ", Pos)) != std::string::npos;359         Pos += strlen(" ")) {360      Type.replace(Pos, strlen("  "), " ");361    }362 363    // Replace " &" with "&".364    for (size_t Pos = 0; (Pos = Type.find(" &", Pos)) != std::string::npos;365         Pos += strlen("&")) {366      Type.replace(Pos, strlen(" &"), "&");367    }368 369    // Replace " *" with "* ".370    for (size_t Pos = 0; (Pos = Type.find(" *", Pos)) != std::string::npos;371         Pos += strlen("*")) {372      Type.replace(Pos, strlen(" *"), "* ");373    }374 375    // Remove redundant tailing.376    static constexpr StringRef TailsOfMultiWordType[] = {377        " int", " char", " double", " long", " short"};378    bool RedundantRemoved = false;379    for (auto Kw : TailsOfMultiWordType) {380      const size_t Pos = Type.rfind(Kw);381      if (Pos != std::string::npos) {382        const size_t PtrCount = getAsteriskCount(Type, ND);383        Type = Type.substr(0, Pos + Kw.size() + PtrCount);384        RedundantRemoved = true;385        break;386      }387    }388 389    TypeName = Type.erase(0, Type.find_first_not_of(' '));390    if (!RedundantRemoved) {391      const std::size_t FoundSpace = Type.find(' ');392      if (FoundSpace != std::string::npos)393        Type = Type.substr(0, FoundSpace);394    }395 396    TypeName = Type.erase(0, Type.find_first_not_of(' '));397 398    const QualType QT = VD->getType();399    if (!QT.isNull() && QT->isArrayType())400      TypeName.append("[]");401  }402 403  return TypeName;404}405 406IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,407                                             ClangTidyContext *Context)408    : RenamerClangTidyCheck(Name, Context), Context(Context),409      GetConfigPerFile(Options.get("GetConfigPerFile", true)),410      IgnoreFailedSplit(Options.get("IgnoreFailedSplit", false)) {411  auto IterAndInserted = NamingStylesCache.try_emplace(412      llvm::sys::path::parent_path(Context->getCurrentFile()),413      getFileStyleFromOptions(Options));414  assert(IterAndInserted.second && "Couldn't insert Style");415  // Holding a reference to the data in the vector is safe as it should never416  // move.417  MainFileStyle = &IterAndInserted.first->getValue();418}419 420IdentifierNamingCheck::~IdentifierNamingCheck() = default;421 422bool IdentifierNamingCheck::HungarianNotation::checkOptionValid(423    int StyleKindIndex) const {424  if ((StyleKindIndex >= SK_EnumConstant) &&425      (StyleKindIndex <= SK_ConstantParameter))426    return true;427 428  if ((StyleKindIndex >= SK_Parameter) && (StyleKindIndex <= SK_Enum))429    return true;430 431  return false;432}433 434bool IdentifierNamingCheck::HungarianNotation::isOptionEnabled(435    StringRef OptionKey, const llvm::StringMap<std::string> &StrMap) const {436  if (OptionKey.empty())437    return false;438 439  auto Iter = StrMap.find(OptionKey);440  if (Iter == StrMap.end())441    return false;442 443  return *llvm::yaml::parseBool(Iter->getValue());444}445 446void IdentifierNamingCheck::HungarianNotation::loadFileConfig(447    const ClangTidyCheck::OptionsView &Options,448    IdentifierNamingCheck::HungarianNotationOption &HNOption) const {449  static constexpr StringRef HNOpts[] = {"TreatStructAsClass"};450  static constexpr StringRef HNDerivedTypes[] = {"Array", "Pointer",451                                                 "FunctionPointer"};452 453  const 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    const 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    const 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    const 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 : HungarianNotationPrimitiveTypes) {494    Buffer.truncate(DefSize);495    Buffer.append(PrimType);496    const StringRef Val = Options.get(Buffer, "");497    if (!Val.empty()) {498      std::string Type = PrimType.str();499      llvm::replace(Type, '-', ' ');500      HNOption.PrimitiveType[Type] = Val.str();501    }502  }503 504  Buffer = {Section, "UserDefinedType."};505  DefSize = Buffer.size();506  for (const auto &Type : HungarianNotationUserDefinedTypes) {507    Buffer.truncate(DefSize);508    Buffer.append(Type);509    const StringRef Val = Options.get(Buffer, "");510    if (!Val.empty())511      HNOption.UserDefinedType[Type] = Val.str();512  }513}514 515std::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    const std::string TypeName = getDeclTypeName(ND);531    if (!TypeName.empty())532      Prefix = getDataTypePrefix(TypeName, ND, HNOption);533  }534 535  return Prefix;536}537 538bool IdentifierNamingCheck::HungarianNotation::removeDuplicatedPrefix(539    SmallVector<StringRef, 8> &Words,540    const IdentifierNamingCheck::HungarianNotationOption &HNOption) const {541  if (Words.size() <= 1)542    return true;543 544  const std::string CorrectName = Words[0].str();545  const 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 561std::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 types570  std::string PrefixStr;571  if (const auto *TD = dyn_cast<ValueDecl>(ND)) {572    const 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        const 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        const 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      const size_t Pos = ModifiedTypeName.find_last_of('&');597      if (Pos != std::string::npos)598        ModifiedTypeName = ModifiedTypeName.substr(0, Pos);599    }600  }601 602  // Pointers603  const 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, StartPos)) != std::string::npos) {608        Str.replace(StartPos, From.size(), To);609        StartPos += To.size();610      }611      return Str;612    }(ModifiedTypeName, "*", "");613  }614 615  // Primitive types616  if (PrefixStr.empty()) {617    for (const auto &Type : HNOption.PrimitiveType) {618      if (ModifiedTypeName == Type.getKey()) {619        PrefixStr = Type.getValue();620        break;621      }622    }623  }624 625  // User-Defined types626  if (PrefixStr.empty()) {627    for (const auto &Type : HNOption.UserDefinedType) {628      if (ModifiedTypeName == Type.getKey()) {629        PrefixStr = Type.getValue();630        break;631      }632    }633  }634 635  for (size_t Idx = 0; Idx < PtrCount; Idx++)636    PrefixStr.insert(0, HNOption.DerivedType.lookup("Pointer"));637 638  return PrefixStr;639}640 641std::string IdentifierNamingCheck::HungarianNotation::getClassPrefix(642    const CXXRecordDecl *CRD,643    const IdentifierNamingCheck::HungarianNotationOption &HNOption) const {644  if (CRD->isUnion())645    return {};646 647  if (CRD->isStruct() &&648      !isOptionEnabled("TreatStructAsClass", HNOption.General))649    return {};650 651  return CRD->isAbstract() ? "I" : "C";652}653 654std::string IdentifierNamingCheck::HungarianNotation::getEnumPrefix(655    const EnumConstantDecl *ECD) const {656  const auto *ED = cast<EnumDecl>(ECD->getDeclContext());657 658  std::string Name = ED->getName().str();659  if (StringRef(Name).contains("enum")) {660    Name = Name.substr(strlen("enum"), Name.length() - strlen("enum"));661    Name = Name.erase(0, Name.find_first_not_of(' '));662  }663 664  static const llvm::Regex Splitter(665      "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");666 667  const StringRef EnumName(Name);668  SmallVector<StringRef, 8> Substrs;669  EnumName.split(Substrs, "_", -1, false);670 671  SmallVector<StringRef, 8> Words;672  SmallVector<StringRef, 8> Groups;673  for (auto Substr : Substrs) {674    while (!Substr.empty()) {675      Groups.clear();676      if (!Splitter.match(Substr, &Groups))677        break;678 679      if (!Groups[2].empty()) {680        Words.push_back(Groups[1]);681        Substr = Substr.substr(Groups[0].size());682      } else if (!Groups[3].empty()) {683        Words.push_back(Groups[3]);684        Substr = Substr.substr(Groups[0].size() - Groups[4].size());685      } else if (!Groups[5].empty()) {686        Words.push_back(Groups[5]);687        Substr = Substr.substr(Groups[0].size() - Groups[6].size());688      }689    }690  }691 692  std::string Initial;693  for (const StringRef Word : Words)694    Initial += tolower(Word[0]);695 696  return Initial;697}698 699size_t IdentifierNamingCheck::HungarianNotation::getAsteriskCount(700    const std::string &TypeName) const {701  size_t Pos = TypeName.find('*');702  size_t Count = 0;703  for (; Pos < TypeName.length(); Pos++, Count++) {704    if ('*' != TypeName[Pos])705      break;706  }707  return Count;708}709 710size_t IdentifierNamingCheck::HungarianNotation::getAsteriskCount(711    const std::string &TypeName, const NamedDecl *ND) const {712  size_t PtrCount = 0;713  if (const auto *TD = dyn_cast<ValueDecl>(ND)) {714    const QualType QT = TD->getType();715    if (QT->isPointerType())716      PtrCount = getAsteriskCount(TypeName);717  }718  return PtrCount;719}720 721void IdentifierNamingCheck::HungarianNotation::loadDefaultConfig(722    IdentifierNamingCheck::HungarianNotationOption &HNOption) const {723  // Options724  static constexpr std::pair<StringRef, StringRef> General[] = {725      {"TreatStructAsClass", "false"}};726  for (const auto &G : General)727    HNOption.General.try_emplace(G.first, G.second);728 729  // Derived types730  static constexpr std::pair<StringRef, StringRef> DerivedTypes[] = {731      {"Array", "a"}, {"Pointer", "p"}, {"FunctionPointer", "fn"}};732  for (const auto &DT : DerivedTypes)733    HNOption.DerivedType.try_emplace(DT.first, DT.second);734 735  // C strings736  static constexpr std::pair<StringRef, StringRef> CStrings[] = {737      {"char*", "sz"},738      {"char[]", "sz"},739      {"wchar_t*", "wsz"},740      {"wchar_t[]", "wsz"}};741  for (const auto &CStr : CStrings)742    HNOption.CString.try_emplace(CStr.first, CStr.second);743 744  // clang-format off745  static constexpr std::pair<StringRef, StringRef> PrimitiveTypes[] = {746        {"int8_t",                  "i8"  },747        {"int16_t",                 "i16" },748        {"int32_t",                 "i32" },749        {"int64_t",                 "i64" },750        {"uint8_t",                 "u8"  },751        {"uint16_t",                "u16" },752        {"uint32_t",                "u32" },753        {"uint64_t",                "u64" },754        {"char8_t",                 "c8"  },755        {"char16_t",                "c16" },756        {"char32_t",                "c32" },757        {"float",                   "f"   },758        {"double",                  "d"   },759        {"char",                    "c"   },760        {"bool",                    "b"   },761        {"_Bool",                   "b"   },762        {"int",                     "i"   },763        {"size_t",                  "n"   },764        {"wchar_t",                 "wc"  },765        {"short int",               "si"  },766        {"short",                   "s"   },767        {"signed int",              "si"  },768        {"signed short",            "ss"  },769        {"signed short int",        "ssi" },770        {"signed long long int",    "slli"},771        {"signed long long",        "sll" },772        {"signed long int",         "sli" },773        {"signed long",             "sl"  },774        {"signed",                  "s"   },775        {"unsigned long long int",  "ulli"},776        {"unsigned long long",      "ull" },777        {"unsigned long int",       "uli" },778        {"unsigned long",           "ul"  },779        {"unsigned short int",      "usi" },780        {"unsigned short",          "us"  },781        {"unsigned int",            "ui"  },782        {"unsigned char",           "uc"  },783        {"unsigned",                "u"   },784        {"long long int",           "lli" },785        {"long double",             "ld"  },786        {"long long",               "ll"  },787        {"long int",                "li"  },788        {"long",                    "l"   },789        {"ptrdiff_t",               "p"   },790        {"void",                    ""    }};791  // clang-format on792  for (const auto &PT : PrimitiveTypes)793    HNOption.PrimitiveType.try_emplace(PT.first, PT.second);794 795  // clang-format off796  static constexpr std::pair<StringRef, StringRef> UserDefinedTypes[] = {797      // Windows data types798      {"BOOL",                    "b"   },799      {"BOOLEAN",                 "b"   },800      {"BYTE",                    "by"  },801      {"CHAR",                    "c"   },802      {"UCHAR",                   "uc"  },803      {"SHORT",                   "s"   },804      {"USHORT",                  "us"  },805      {"WORD",                    "w"   },806      {"DWORD",                   "dw"  },807      {"DWORD32",                 "dw32"},808      {"DWORD64",                 "dw64"},809      {"LONG",                    "l"   },810      {"ULONG",                   "ul"  },811      {"ULONG32",                 "ul32"},812      {"ULONG64",                 "ul64"},813      {"ULONGLONG",               "ull" },814      {"HANDLE",                  "h"   },815      {"INT",                     "i"   },816      {"INT8",                    "i8"  },817      {"INT16",                   "i16" },818      {"INT32",                   "i32" },819      {"INT64",                   "i64" },820      {"UINT",                    "ui"  },821      {"UINT8",                   "u8"  },822      {"UINT16",                  "u16" },823      {"UINT32",                  "u32" },824      {"UINT64",                  "u64" },825      {"PVOID",                   "p"   } };826  // clang-format on827  for (const auto &UDT : UserDefinedTypes)828    HNOption.UserDefinedType.try_emplace(UDT.first, UDT.second);829}830 831void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {832  RenamerClangTidyCheck::storeOptions(Opts);833  SmallString<64> StyleString;834  const ArrayRef<std::optional<NamingStyle>> Styles =835      MainFileStyle->getStyles();836  for (size_t I = 0; I < SK_Count; ++I) {837    if (!Styles[I])838      continue;839    const size_t StyleSize = StyleNames[I].size();840    StyleString.assign({StyleNames[I], "HungarianPrefix"});841 842    Options.store(Opts, StyleString, Styles[I]->HPType);843 844    memcpy(&StyleString[StyleSize], "IgnoredRegexp", 13);845    StyleString.truncate(StyleSize + 13);846    Options.store(Opts, StyleString, Styles[I]->IgnoredRegexpStr);847    memcpy(&StyleString[StyleSize], "Prefix", 6);848    StyleString.truncate(StyleSize + 6);849    Options.store(Opts, StyleString, Styles[I]->Prefix);850    // Fast replacement of [Pre]fix -> [Suf]fix.851    memcpy(&StyleString[StyleSize], "Suf", 3);852    Options.store(Opts, StyleString, Styles[I]->Suffix);853    if (Styles[I]->Case) {854      memcpy(&StyleString[StyleSize], "Case", 4);855      StyleString.pop_back_n(2);856      Options.store(Opts, StyleString, *Styles[I]->Case);857    }858  }859  Options.store(Opts, "GetConfigPerFile", GetConfigPerFile);860  Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);861  Options.store(Opts, "IgnoreMainLikeFunctions",862                MainFileStyle->isIgnoringMainLikeFunction());863  Options.store(Opts, "CheckAnonFieldInParent",864                MainFileStyle->isCheckingAnonFieldInParentScope());865}866 867bool IdentifierNamingCheck::matchesStyle(868    StringRef Type, StringRef Name,869    const IdentifierNamingCheck::NamingStyle &Style,870    const IdentifierNamingCheck::HungarianNotationOption &HNOption,871    const NamedDecl *Decl) const {872  static const llvm::Regex Matchers[] = {873      llvm::Regex("^.*$"),874      llvm::Regex("^[a-z][a-z0-9_]*$"),875      llvm::Regex("^[a-z][a-zA-Z0-9]*$"),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]*_[A-Z0-9]+)*[a-z0-9]*$"),879      llvm::Regex("^[a-z]+([a-z0-9]*_[A-Z0-9]+)*[a-z0-9]*$"),880      llvm::Regex("^[A-Z]([a-z0-9_]*[a-z])*$"),881  };882 883  if (!Name.consume_front(Style.Prefix))884    return false;885  if (!Name.consume_back(Style.Suffix))886    return false;887  if (IdentifierNamingCheck::HungarianPrefixType::HPT_Off != Style.HPType) {888    const std::string HNPrefix = HungarianNotation.getPrefix(Decl, HNOption);889    if (!HNPrefix.empty()) {890      if (!Name.consume_front(HNPrefix))891        return false;892      if (Style.HPType ==893              IdentifierNamingCheck::HungarianPrefixType::HPT_LowerCase &&894          !Name.consume_front("_"))895        return false;896    }897  }898 899  // Ensure the name doesn't have any extra underscores beyond those specified900  // in the prefix and suffix.901  if (Name.starts_with("_") || Name.ends_with("_"))902    return false;903 904  if (Style.Case && !Matchers[static_cast<size_t>(*Style.Case)].match(Name))905    return false;906 907  return true;908}909 910std::string IdentifierNamingCheck::fixupWithCase(911    StringRef Type, StringRef Name, const Decl *D,912    const IdentifierNamingCheck::NamingStyle &Style,913    const IdentifierNamingCheck::HungarianNotationOption &HNOption,914    IdentifierNamingCheck::CaseType Case) const {915  static const llvm::Regex Splitter(916      "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");917 918  SmallVector<StringRef, 8> Substrs;919  Name.split(Substrs, "_", -1, false);920 921  SmallVector<StringRef, 8> Words;922  SmallVector<StringRef, 8> Groups;923  for (auto Substr : Substrs) {924    while (!Substr.empty()) {925      Groups.clear();926      if (!Splitter.match(Substr, &Groups))927        break;928 929      if (!Groups[2].empty()) {930        Words.push_back(Groups[1]);931        Substr = Substr.substr(Groups[0].size());932      } else if (!Groups[3].empty()) {933        Words.push_back(Groups[3]);934        Substr = Substr.substr(Groups[0].size() - Groups[4].size());935      } else if (!Groups[5].empty()) {936        Words.push_back(Groups[5]);937        Substr = Substr.substr(Groups[0].size() - Groups[6].size());938      }939    }940  }941 942  if (Words.empty())943    return Name.str();944 945  if (IdentifierNamingCheck::HungarianPrefixType::HPT_Off != Style.HPType) {946    HungarianNotation.removeDuplicatedPrefix(Words, HNOption);947  }948 949  SmallString<128> Fixup;950  switch (Case) {951  case IdentifierNamingCheck::CT_AnyCase:952    return Name.str();953    break;954 955  case IdentifierNamingCheck::CT_LowerCase:956    for (const auto &Word : Words) {957      if (&Word != &Words.front())958        Fixup += "_";959      Fixup += Word.lower();960    }961    break;962 963  case IdentifierNamingCheck::CT_UpperCase:964    for (const auto &Word : Words) {965      if (&Word != &Words.front())966        Fixup += "_";967      Fixup += Word.upper();968    }969    break;970 971  case IdentifierNamingCheck::CT_CamelCase:972    for (const auto &Word : Words) {973      Fixup += toupper(Word.front());974      Fixup += Word.substr(1).lower();975    }976    break;977 978  case IdentifierNamingCheck::CT_CamelBack:979    for (const auto &Word : Words) {980      if (&Word == &Words.front()) {981        Fixup += Word.lower();982      } else {983        Fixup += toupper(Word.front());984        Fixup += Word.substr(1).lower();985      }986    }987    break;988 989  case IdentifierNamingCheck::CT_CamelSnakeCase:990    for (const auto &Word : Words) {991      if (&Word != &Words.front())992        Fixup += "_";993      Fixup += toupper(Word.front());994      Fixup += Word.substr(1).lower();995    }996    break;997 998  case IdentifierNamingCheck::CT_CamelSnakeBack:999    for (const auto &Word : Words) {1000      if (&Word != &Words.front()) {1001        Fixup += "_";1002        Fixup += toupper(Word.front());1003      } else {1004        Fixup += tolower(Word.front());1005      }1006      Fixup += Word.substr(1).lower();1007    }1008    break;1009 1010  case IdentifierNamingCheck::CT_LeadingUpperSnakeCase:1011    for (const auto &Word : Words) {1012      if (&Word != &Words.front()) {1013        Fixup += "_";1014        Fixup += Word.lower();1015      } else {1016        Fixup += toupper(Word.front());1017        Fixup += Word.substr(1).lower();1018      }1019    }1020    break;1021  }1022 1023  return Fixup.str().str();1024}1025 1026bool IdentifierNamingCheck::isParamInMainLikeFunction(1027    const ParmVarDecl &ParmDecl, bool IncludeMainLike) const {1028  const auto *FDecl =1029      dyn_cast_or_null<FunctionDecl>(ParmDecl.getParentFunctionOrMethod());1030  if (!FDecl)1031    return false;1032  if (FDecl->isMain())1033    return true;1034  if (!IncludeMainLike)1035    return false;1036  if (FDecl->getAccess() != AS_public && FDecl->getAccess() != AS_none)1037    return false;1038  // If the function doesn't have a name that's an identifier, can occur if the1039  // function is an operator overload, bail out early.1040  if (!FDecl->getDeclName().isIdentifier())1041    return false;1042  enum MainType { None, Main, WMain };1043  auto IsCharPtrPtr = [](QualType QType) -> MainType {1044    if (QType.isNull())1045      return None;1046    if (QType = QType->getPointeeType(), QType.isNull())1047      return None;1048    if (QType = QType->getPointeeType(), QType.isNull())1049      return None;1050    if (QType->isCharType())1051      return Main;1052    if (QType->isWideCharType())1053      return WMain;1054    return None;1055  };1056  auto IsIntType = [](QualType QType) {1057    if (QType.isNull())1058      return false;1059    if (const auto *Builtin =1060            dyn_cast<BuiltinType>(QType->getUnqualifiedDesugaredType())) {1061      return Builtin->getKind() == BuiltinType::Int;1062    }1063    return false;1064  };1065  if (!IsIntType(FDecl->getReturnType()))1066    return false;1067  if (FDecl->getNumParams() < 2 || FDecl->getNumParams() > 3)1068    return false;1069  if (!IsIntType(FDecl->parameters()[0]->getType()))1070    return false;1071  const MainType Type = IsCharPtrPtr(FDecl->parameters()[1]->getType());1072  if (Type == None)1073    return false;1074  if (FDecl->getNumParams() == 3 &&1075      IsCharPtrPtr(FDecl->parameters()[2]->getType()) != Type)1076    return false;1077 1078  if (Type == Main) {1079    static const llvm::Regex Matcher(1080        "(^[Mm]ain([_A-Z]|$))|([a-z0-9_]Main([_A-Z]|$))|(_main(_|$))");1081    assert(Matcher.isValid() && "Invalid Matcher for main like functions.");1082    return Matcher.match(FDecl->getName());1083  }1084  static const llvm::Regex Matcher(1085      "(^((W[Mm])|(wm))ain([_A-Z]|$))|([a-z0-9_]W[Mm]"1086      "ain([_A-Z]|$))|(_wmain(_|$))");1087  assert(Matcher.isValid() && "Invalid Matcher for wmain like functions.");1088  return Matcher.match(FDecl->getName());1089}1090 1091std::string IdentifierNamingCheck::fixupWithStyle(1092    StringRef Type, StringRef Name,1093    const IdentifierNamingCheck::NamingStyle &Style,1094    const IdentifierNamingCheck::HungarianNotationOption &HNOption,1095    const Decl *D) const {1096  Name.consume_front(Style.Prefix);1097  Name.consume_back(Style.Suffix);1098  std::string Fixed = fixupWithCase(1099      Type, Name, D, Style, HNOption,1100      Style.Case.value_or(IdentifierNamingCheck::CaseType::CT_AnyCase));1101 1102  std::string HungarianPrefix;1103  using HungarianPrefixType = IdentifierNamingCheck::HungarianPrefixType;1104  if (HungarianPrefixType::HPT_Off != Style.HPType) {1105    HungarianPrefix = HungarianNotation.getPrefix(D, HNOption);1106    if (!HungarianPrefix.empty()) {1107      if (Style.HPType == HungarianPrefixType::HPT_LowerCase)1108        HungarianPrefix += "_";1109 1110      if (Style.HPType == HungarianPrefixType::HPT_CamelCase)1111        Fixed[0] = toupper(Fixed[0]);1112    }1113  }1114  StringRef Mid = StringRef(Fixed).trim("_");1115  if (Mid.empty())1116    Mid = "_";1117 1118  return (Style.Prefix + HungarianPrefix + Mid + Style.Suffix).str();1119}1120 1121StyleKind IdentifierNamingCheck::findStyleKind(1122    const NamedDecl *D,1123    ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles,1124    bool IgnoreMainLikeFunctions, bool CheckAnonFieldInParentScope) const {1125  assert(D && D->getIdentifier() && !D->getName().empty() && !D->isImplicit() &&1126         "Decl must be an explicit identifier with a name.");1127 1128  if (isa<ObjCIvarDecl>(D) && NamingStyles[SK_ObjcIvar])1129    return SK_ObjcIvar;1130 1131  if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef])1132    return SK_Typedef;1133 1134  if (isa<TypeAliasDecl>(D) && NamingStyles[SK_TypeAlias])1135    return SK_TypeAlias;1136 1137  if (isa<NamespaceAliasDecl>(D) && NamingStyles[SK_Namespace])1138    return SK_Namespace;1139 1140  if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) {1141    if (Decl->isAnonymousNamespace())1142      return SK_Invalid;1143 1144    if (Decl->isInline() && NamingStyles[SK_InlineNamespace])1145      return SK_InlineNamespace;1146 1147    if (NamingStyles[SK_Namespace])1148      return SK_Namespace;1149  }1150 1151  if (isa<EnumDecl>(D) && NamingStyles[SK_Enum])1152    return SK_Enum;1153 1154  if (const auto *EnumConst = dyn_cast<EnumConstantDecl>(D)) {1155    if (cast<EnumDecl>(EnumConst->getDeclContext())->isScoped() &&1156        NamingStyles[SK_ScopedEnumConstant])1157      return SK_ScopedEnumConstant;1158 1159    if (NamingStyles[SK_EnumConstant])1160      return SK_EnumConstant;1161 1162    if (NamingStyles[SK_Constant])1163      return SK_Constant;1164 1165    return SK_Invalid;1166  }1167 1168  if (const auto *Decl = dyn_cast<RecordDecl>(D)) {1169    if (Decl->isAnonymousStructOrUnion())1170      return SK_Invalid;1171 1172    if (const auto *Definition = Decl->getDefinition()) {1173      if (const auto *CxxRecordDecl = dyn_cast<CXXRecordDecl>(Definition)) {1174        if (CxxRecordDecl->isAbstract() && NamingStyles[SK_AbstractClass])1175          return SK_AbstractClass;1176      }1177 1178      if (Definition->isStruct() && NamingStyles[SK_Struct])1179        return SK_Struct;1180 1181      if (Definition->isStruct() && NamingStyles[SK_Class])1182        return SK_Class;1183 1184      if (Definition->isClass() && NamingStyles[SK_Class])1185        return SK_Class;1186 1187      if (Definition->isClass() && NamingStyles[SK_Struct])1188        return SK_Struct;1189 1190      if (Definition->isUnion() && NamingStyles[SK_Union])1191        return SK_Union;1192 1193      if (Definition->isEnum() && NamingStyles[SK_Enum])1194        return SK_Enum;1195    }1196 1197    return SK_Invalid;1198  }1199 1200  if (const auto *Decl = dyn_cast<FieldDecl>(D)) {1201    if (CheckAnonFieldInParentScope) {1202      const RecordDecl *Record = Decl->getParent();1203      if (Record->isAnonymousStructOrUnion()) {1204        return findStyleKindForAnonField(Decl, NamingStyles);1205      }1206    }1207 1208    return findStyleKindForField(Decl, Decl->getType(), NamingStyles);1209  }1210 1211  if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {1212    if (isParamInMainLikeFunction(*Decl, IgnoreMainLikeFunctions))1213      return SK_Invalid;1214    const QualType Type = Decl->getType();1215 1216    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])1217      return SK_ConstexprVariable;1218 1219    if (!Type.isNull() && Type.isConstQualified()) {1220      if (Type.getTypePtr()->isAnyPointerType() &&1221          NamingStyles[SK_ConstantPointerParameter])1222        return SK_ConstantPointerParameter;1223 1224      if (NamingStyles[SK_ConstantParameter])1225        return SK_ConstantParameter;1226 1227      if (NamingStyles[SK_Constant])1228        return SK_Constant;1229    }1230 1231    if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack])1232      return SK_ParameterPack;1233 1234    if (!Type.isNull() && Type.getTypePtr()->isAnyPointerType() &&1235        NamingStyles[SK_PointerParameter])1236      return SK_PointerParameter;1237 1238    if (NamingStyles[SK_Parameter])1239      return SK_Parameter;1240 1241    return SK_Invalid;1242  }1243 1244  if (const auto *Decl = dyn_cast<VarDecl>(D)) {1245    return findStyleKindForVar(Decl, Decl->getType(), NamingStyles);1246  }1247 1248  if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {1249    if (Decl->isMain() || !Decl->isUserProvided() ||1250        Decl->size_overridden_methods() > 0 || Decl->hasAttr<OverrideAttr>())1251      return SK_Invalid;1252 1253    // If this method has the same name as any base method, this is likely1254    // necessary even if it's not an override. e.g. CRTP.1255    for (const CXXBaseSpecifier &Base : Decl->getParent()->bases())1256      if (const auto *RD = Base.getType()->getAsCXXRecordDecl())1257        if (RD->hasMemberName(Decl->getDeclName()))1258          return SK_Invalid;1259 1260    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod])1261      return SK_ConstexprMethod;1262 1263    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])1264      return SK_ConstexprFunction;1265 1266    if (Decl->isStatic() && NamingStyles[SK_ClassMethod])1267      return SK_ClassMethod;1268 1269    if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod])1270      return SK_VirtualMethod;1271 1272    if (Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMethod])1273      return SK_PrivateMethod;1274 1275    if (Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMethod])1276      return SK_ProtectedMethod;1277 1278    if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod])1279      return SK_PublicMethod;1280 1281    if (NamingStyles[SK_Method])1282      return SK_Method;1283 1284    if (NamingStyles[SK_Function])1285      return SK_Function;1286 1287    return SK_Invalid;1288  }1289 1290  if (const auto *Decl = dyn_cast<FunctionDecl>(D)) {1291    if (Decl->isMain())1292      return SK_Invalid;1293 1294    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])1295      return SK_ConstexprFunction;1296 1297    if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction])1298      return SK_GlobalFunction;1299 1300    if (NamingStyles[SK_Function])1301      return SK_Function;1302  }1303 1304  if (isa<TemplateTypeParmDecl>(D)) {1305    if (NamingStyles[SK_TypeTemplateParameter])1306      return SK_TypeTemplateParameter;1307 1308    if (NamingStyles[SK_TemplateParameter])1309      return SK_TemplateParameter;1310 1311    return SK_Invalid;1312  }1313 1314  if (isa<NonTypeTemplateParmDecl>(D)) {1315    if (NamingStyles[SK_ValueTemplateParameter])1316      return SK_ValueTemplateParameter;1317 1318    if (NamingStyles[SK_TemplateParameter])1319      return SK_TemplateParameter;1320 1321    return SK_Invalid;1322  }1323 1324  if (isa<TemplateTemplateParmDecl>(D)) {1325    if (NamingStyles[SK_TemplateTemplateParameter])1326      return SK_TemplateTemplateParameter;1327 1328    if (NamingStyles[SK_TemplateParameter])1329      return SK_TemplateParameter;1330 1331    return SK_Invalid;1332  }1333 1334  if (isa<ConceptDecl>(D) && NamingStyles[SK_Concept])1335    return SK_Concept;1336 1337  return SK_Invalid;1338}1339 1340std::optional<RenamerClangTidyCheck::FailureInfo>1341IdentifierNamingCheck::getFailureInfo(1342    StringRef Type, StringRef Name, const NamedDecl *ND,1343    SourceLocation Location,1344    ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles,1345    const IdentifierNamingCheck::HungarianNotationOption &HNOption,1346    StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) const {1347  if (SK == SK_Invalid || !NamingStyles[SK])1348    return std::nullopt;1349 1350  const IdentifierNamingCheck::NamingStyle &Style = *NamingStyles[SK];1351  if (Style.IgnoredRegexp.isValid() && Style.IgnoredRegexp.match(Name))1352    return std::nullopt;1353 1354  if (matchesStyle(Type, Name, Style, HNOption, ND))1355    return std::nullopt;1356 1357  std::string KindName =1358      fixupWithCase(Type, StyleNames[SK], ND, Style, HNOption,1359                    IdentifierNamingCheck::CT_LowerCase);1360  llvm::replace(KindName, '_', ' ');1361 1362  std::string Fixup = fixupWithStyle(Type, Name, Style, HNOption, ND);1363  if (StringRef(Fixup) == Name) {1364    if (!IgnoreFailedSplit) {1365      LLVM_DEBUG(Location.print(llvm::dbgs(), SM);1366                 llvm::dbgs()1367                 << llvm::formatv(": unable to split words for {0} '{1}'\n",1368                                  KindName, Name));1369    }1370    return std::nullopt;1371  }1372  return RenamerClangTidyCheck::FailureInfo{std::move(KindName),1373                                            std::move(Fixup)};1374}1375 1376std::optional<RenamerClangTidyCheck::FailureInfo>1377IdentifierNamingCheck::getDeclFailureInfo(const NamedDecl *Decl,1378                                          const SourceManager &SM) const {1379  // Implicit identifiers cannot be renamed.1380  if (Decl->isImplicit())1381    return std::nullopt;1382 1383  const SourceLocation Loc = Decl->getLocation();1384  const FileStyle &FileStyle = getStyleForFile(SM.getFilename(Loc));1385  if (!FileStyle.isActive())1386    return std::nullopt;1387 1388  return getFailureInfo(1389      HungarianNotation.getDeclTypeName(Decl), Decl->getName(), Decl, Loc,1390      FileStyle.getStyles(), FileStyle.getHNOption(),1391      findStyleKind(Decl, FileStyle.getStyles(),1392                    FileStyle.isIgnoringMainLikeFunction(),1393                    FileStyle.isCheckingAnonFieldInParentScope()),1394      SM, IgnoreFailedSplit);1395}1396 1397std::optional<RenamerClangTidyCheck::FailureInfo>1398IdentifierNamingCheck::getMacroFailureInfo(const Token &MacroNameTok,1399                                           const SourceManager &SM) const {1400  const SourceLocation Loc = MacroNameTok.getLocation();1401  const FileStyle &Style = getStyleForFile(SM.getFilename(Loc));1402  if (!Style.isActive())1403    return std::nullopt;1404 1405  return getFailureInfo("", MacroNameTok.getIdentifierInfo()->getName(),1406                        nullptr, Loc, Style.getStyles(), Style.getHNOption(),1407                        SK_MacroDefinition, SM, IgnoreFailedSplit);1408}1409 1410RenamerClangTidyCheck::DiagInfo1411IdentifierNamingCheck::getDiagInfo(const NamingCheckId &ID,1412                                   const NamingCheckFailure &Failure) const {1413  return DiagInfo{"invalid case style for %0 '%1'",1414                  [&](DiagnosticBuilder &Diag) {1415                    Diag << Failure.Info.KindName << ID.second;1416                  }};1417}1418 1419StringRef IdentifierNamingCheck::getRealFileName(StringRef FileName) const {1420  auto Iter = RealFileNameCache.try_emplace(FileName);1421  SmallString<256U> &RealFileName = Iter.first->getValue();1422  if (!Iter.second)1423    return RealFileName;1424  llvm::sys::fs::real_path(FileName, RealFileName);1425  return RealFileName;1426}1427 1428const IdentifierNamingCheck::FileStyle &1429IdentifierNamingCheck::getStyleForFile(StringRef FileName) const {1430  if (!GetConfigPerFile)1431    return *MainFileStyle;1432 1433  const StringRef RealFileName = getRealFileName(FileName);1434  const StringRef Parent = llvm::sys::path::parent_path(RealFileName);1435  auto Iter = NamingStylesCache.find(Parent);1436  if (Iter != NamingStylesCache.end())1437    return Iter->getValue();1438 1439  const llvm::StringRef CheckName = getID();1440  ClangTidyOptions Options = Context->getOptionsForFile(RealFileName);1441  if (Options.Checks && GlobList(*Options.Checks).contains(CheckName)) {1442    auto It = NamingStylesCache.try_emplace(1443        Parent,1444        getFileStyleFromOptions({CheckName, Options.CheckOptions, Context}));1445    assert(It.second);1446    return It.first->getValue();1447  }1448  // Default construction gives an empty style.1449  auto It = NamingStylesCache.try_emplace(Parent);1450  assert(It.second);1451  return It.first->getValue();1452}1453 1454StyleKind IdentifierNamingCheck::findStyleKindForAnonField(1455    const FieldDecl *AnonField,1456    ArrayRef<std::optional<NamingStyle>> NamingStyles) const {1457  const IndirectFieldDecl *IFD =1458      utils::findOutermostIndirectFieldDeclForField(AnonField);1459  assert(IFD && "Found an anonymous record field without an IndirectFieldDecl");1460 1461  const QualType Type = AnonField->getType();1462 1463  if (const auto *F = dyn_cast<FieldDecl>(IFD->chain().front())) {1464    return findStyleKindForField(F, Type, NamingStyles);1465  }1466 1467  if (const auto *V = IFD->getVarDecl()) {1468    return findStyleKindForVar(V, Type, NamingStyles);1469  }1470 1471  return SK_Invalid;1472}1473 1474StyleKind IdentifierNamingCheck::findStyleKindForField(1475    const FieldDecl *Field, QualType Type,1476    ArrayRef<std::optional<NamingStyle>> NamingStyles) const {1477  if (!Type.isNull() && Type.isConstQualified()) {1478    if (NamingStyles[SK_ConstantMember])1479      return SK_ConstantMember;1480 1481    if (NamingStyles[SK_Constant])1482      return SK_Constant;1483  }1484 1485  if (Field->getAccess() == AS_private && NamingStyles[SK_PrivateMember])1486    return SK_PrivateMember;1487 1488  if (Field->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember])1489    return SK_ProtectedMember;1490 1491  if (Field->getAccess() == AS_public && NamingStyles[SK_PublicMember])1492    return SK_PublicMember;1493 1494  if (NamingStyles[SK_Member])1495    return SK_Member;1496 1497  return SK_Invalid;1498}1499 1500StyleKind IdentifierNamingCheck::findStyleKindForVar(1501    const VarDecl *Var, QualType Type,1502    ArrayRef<std::optional<NamingStyle>> NamingStyles) const {1503  if (Var->isConstexpr()) {1504    if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstexpr])1505      return SK_ClassConstexpr;1506 1507    if (Var->isFileVarDecl() && NamingStyles[SK_GlobalConstexprVariable])1508      return SK_GlobalConstexprVariable;1509 1510    if (Var->isStaticLocal() && NamingStyles[SK_StaticConstexprVariable])1511      return SK_StaticConstexprVariable;1512 1513    if (Var->isLocalVarDecl() && NamingStyles[SK_LocalConstexprVariable])1514      return SK_LocalConstexprVariable;1515 1516    if (NamingStyles[SK_ConstexprVariable])1517      return SK_ConstexprVariable;1518  }1519 1520  if (!Type.isNull() && Type.isConstQualified()) {1521    if (Var->isStaticDataMember() && NamingStyles[SK_ClassConstant])1522      return SK_ClassConstant;1523 1524    if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&1525        NamingStyles[SK_GlobalConstantPointer])1526      return SK_GlobalConstantPointer;1527 1528    if (Var->isFileVarDecl() && NamingStyles[SK_GlobalConstant])1529      return SK_GlobalConstant;1530 1531    if (Var->isStaticLocal() && NamingStyles[SK_StaticConstant])1532      return SK_StaticConstant;1533 1534    if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&1535        NamingStyles[SK_LocalConstantPointer])1536      return SK_LocalConstantPointer;1537 1538    if (Var->isLocalVarDecl() && NamingStyles[SK_LocalConstant])1539      return SK_LocalConstant;1540 1541    if (Var->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant])1542      return SK_LocalConstant;1543 1544    if (NamingStyles[SK_Constant])1545      return SK_Constant;1546  }1547 1548  if (Var->isStaticDataMember() && NamingStyles[SK_ClassMember])1549    return SK_ClassMember;1550 1551  if (Var->isFileVarDecl() && Type.getTypePtr()->isAnyPointerType() &&1552      NamingStyles[SK_GlobalPointer])1553    return SK_GlobalPointer;1554 1555  if (Var->isFileVarDecl() && NamingStyles[SK_GlobalVariable])1556    return SK_GlobalVariable;1557 1558  if (Var->isStaticLocal() && NamingStyles[SK_StaticVariable])1559    return SK_StaticVariable;1560 1561  if (Var->isLocalVarDecl() && Type.getTypePtr()->isAnyPointerType() &&1562      NamingStyles[SK_LocalPointer])1563    return SK_LocalPointer;1564 1565  if (Var->isLocalVarDecl() && NamingStyles[SK_LocalVariable])1566    return SK_LocalVariable;1567 1568  if (Var->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable])1569    return SK_LocalVariable;1570 1571  if (NamingStyles[SK_Variable])1572    return SK_Variable;1573 1574  return SK_Invalid;1575}1576 1577} // namespace readability1578} // namespace clang::tidy1579