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