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