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