blob: 567dbddaa6f783daf858420799f7ce2cc1ebd767 [file] [log] [blame]
Alexander Kornienko76c28802015-08-19 11:15:36 +00001//===--- IdentifierNamingCheck.cpp - clang-tidy ---------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "IdentifierNamingCheck.h"
11
12#include "llvm/Support/Debug.h"
13#include "llvm/Support/Format.h"
14#include "clang/ASTMatchers/ASTMatchFinder.h"
15
16#define DEBUG_TYPE "clang-tidy"
17
18using namespace clang::ast_matchers;
19
20namespace clang {
21namespace tidy {
22namespace readability {
23
Alexander Kornienko3d777682015-09-28 08:59:12 +000024// clang-format off
Alexander Kornienko76c28802015-08-19 11:15:36 +000025#define NAMING_KEYS(m) \
26 m(Namespace) \
27 m(InlineNamespace) \
28 m(EnumConstant) \
29 m(ConstexprVariable) \
30 m(ConstantMember) \
31 m(PrivateMember) \
32 m(ProtectedMember) \
33 m(PublicMember) \
34 m(Member) \
35 m(ClassConstant) \
36 m(ClassMember) \
37 m(GlobalConstant) \
38 m(GlobalVariable) \
39 m(LocalConstant) \
40 m(LocalVariable) \
41 m(StaticConstant) \
42 m(StaticVariable) \
43 m(Constant) \
44 m(Variable) \
45 m(ConstantParameter) \
46 m(ParameterPack) \
47 m(Parameter) \
48 m(AbstractClass) \
49 m(Struct) \
50 m(Class) \
51 m(Union) \
52 m(Enum) \
53 m(GlobalFunction) \
54 m(ConstexprFunction) \
55 m(Function) \
56 m(ConstexprMethod) \
57 m(VirtualMethod) \
58 m(ClassMethod) \
59 m(PrivateMethod) \
60 m(ProtectedMethod) \
61 m(PublicMethod) \
62 m(Method) \
63 m(Typedef) \
64 m(TypeTemplateParameter) \
65 m(ValueTemplateParameter) \
66 m(TemplateTemplateParameter) \
67 m(TemplateParameter) \
Alexander Kornienko5ae76e02016-06-07 09:11:19 +000068 m(TypeAlias) \
Alexander Kornienko76c28802015-08-19 11:15:36 +000069
70enum StyleKind {
71#define ENUMERATE(v) SK_ ## v,
72 NAMING_KEYS(ENUMERATE)
73#undef ENUMERATE
74 SK_Count,
75 SK_Invalid
76};
77
78static StringRef const StyleNames[] = {
79#define STRINGIZE(v) #v,
80 NAMING_KEYS(STRINGIZE)
81#undef STRINGIZE
82};
83
84#undef NAMING_KEYS
Alexander Kornienko3d777682015-09-28 08:59:12 +000085// clang-format on
Alexander Kornienko76c28802015-08-19 11:15:36 +000086
87IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,
88 ClangTidyContext *Context)
89 : ClangTidyCheck(Name, Context) {
90 auto const fromString = [](StringRef Str) {
91 return llvm::StringSwitch<CaseType>(Str)
92 .Case("lower_case", CT_LowerCase)
93 .Case("UPPER_CASE", CT_UpperCase)
94 .Case("camelBack", CT_CamelBack)
95 .Case("CamelCase", CT_CamelCase)
96 .Default(CT_AnyCase);
97 };
98
99 for (auto const &Name : StyleNames) {
100 NamingStyles.push_back(
101 NamingStyle(fromString(Options.get((Name + "Case").str(), "")),
102 Options.get((Name + "Prefix").str(), ""),
103 Options.get((Name + "Suffix").str(), "")));
104 }
105
106 IgnoreFailedSplit = Options.get("IgnoreFailedSplit", 0);
107}
108
109void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
110 auto const toString = [](CaseType Type) {
111 switch (Type) {
112 case CT_AnyCase:
113 return "aNy_CasE";
114 case CT_LowerCase:
115 return "lower_case";
116 case CT_CamelBack:
117 return "camelBack";
118 case CT_UpperCase:
119 return "UPPER_CASE";
120 case CT_CamelCase:
121 return "CamelCase";
122 }
123
124 llvm_unreachable("Unknown Case Type");
125 };
126
127 for (size_t i = 0; i < SK_Count; ++i) {
128 Options.store(Opts, (StyleNames[i] + "Case").str(),
129 toString(NamingStyles[i].Case));
130 Options.store(Opts, (StyleNames[i] + "Prefix").str(),
131 NamingStyles[i].Prefix);
132 Options.store(Opts, (StyleNames[i] + "Suffix").str(),
133 NamingStyles[i].Suffix);
134 }
135
136 Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
137}
138
139void IdentifierNamingCheck::registerMatchers(MatchFinder *Finder) {
Alexander Kornienko76c28802015-08-19 11:15:36 +0000140 Finder->addMatcher(namedDecl().bind("decl"), this);
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000141 Finder->addMatcher(usingDecl().bind("using"), this);
142 Finder->addMatcher(declRefExpr().bind("declRef"), this);
143 Finder->addMatcher(cxxConstructorDecl().bind("classRef"), this);
144 Finder->addMatcher(cxxDestructorDecl().bind("classRef"), this);
145 Finder->addMatcher(typeLoc().bind("typeLoc"), this);
146 Finder->addMatcher(nestedNameSpecifierLoc().bind("nestedNameLoc"), this);
Alexander Kornienko76c28802015-08-19 11:15:36 +0000147}
148
149static bool matchesStyle(StringRef Name,
150 IdentifierNamingCheck::NamingStyle Style) {
151 static llvm::Regex Matchers[] = {
152 llvm::Regex("^.*$"),
153 llvm::Regex("^[a-z][a-z0-9_]*$"),
154 llvm::Regex("^[a-z][a-zA-Z0-9]*$"),
155 llvm::Regex("^[A-Z][A-Z0-9_]*$"),
156 llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
157 };
158
159 bool Matches = true;
160 if (Name.startswith(Style.Prefix))
161 Name = Name.drop_front(Style.Prefix.size());
162 else
163 Matches = false;
164
165 if (Name.endswith(Style.Suffix))
166 Name = Name.drop_back(Style.Suffix.size());
167 else
168 Matches = false;
169
170 if (!Matchers[static_cast<size_t>(Style.Case)].match(Name))
171 Matches = false;
172
173 return Matches;
174}
175
176static std::string fixupWithCase(StringRef Name,
177 IdentifierNamingCheck::CaseType Case) {
178 static llvm::Regex Splitter(
179 "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
180
181 SmallVector<StringRef, 8> Substrs;
182 Name.split(Substrs, "_", -1, false);
183
184 SmallVector<StringRef, 8> Words;
185 for (auto Substr : Substrs) {
186 while (!Substr.empty()) {
187 SmallVector<StringRef, 8> Groups;
188 if (!Splitter.match(Substr, &Groups))
189 break;
190
191 if (Groups[2].size() > 0) {
192 Words.push_back(Groups[1]);
193 Substr = Substr.substr(Groups[0].size());
194 } else if (Groups[3].size() > 0) {
195 Words.push_back(Groups[3]);
196 Substr = Substr.substr(Groups[0].size() - Groups[4].size());
197 } else if (Groups[5].size() > 0) {
198 Words.push_back(Groups[5]);
199 Substr = Substr.substr(Groups[0].size() - Groups[6].size());
200 }
201 }
202 }
203
204 if (Words.empty())
205 return Name;
206
207 std::string Fixup;
208 switch (Case) {
209 case IdentifierNamingCheck::CT_AnyCase:
210 Fixup += Name;
211 break;
212
213 case IdentifierNamingCheck::CT_LowerCase:
214 for (auto const &Word : Words) {
215 if (&Word != &Words.front())
216 Fixup += "_";
217 Fixup += Word.lower();
218 }
219 break;
220
221 case IdentifierNamingCheck::CT_UpperCase:
222 for (auto const &Word : Words) {
223 if (&Word != &Words.front())
224 Fixup += "_";
225 Fixup += Word.upper();
226 }
227 break;
228
229 case IdentifierNamingCheck::CT_CamelCase:
230 for (auto const &Word : Words) {
231 Fixup += Word.substr(0, 1).upper();
232 Fixup += Word.substr(1).lower();
233 }
234 break;
235
236 case IdentifierNamingCheck::CT_CamelBack:
237 for (auto const &Word : Words) {
238 if (&Word == &Words.front()) {
239 Fixup += Word.lower();
240 } else {
241 Fixup += Word.substr(0, 1).upper();
242 Fixup += Word.substr(1).lower();
243 }
244 }
245 break;
246 }
247
248 return Fixup;
249}
250
251static std::string fixupWithStyle(StringRef Name,
252 IdentifierNamingCheck::NamingStyle Style) {
253 return Style.Prefix + fixupWithCase(Name, Style.Case) + Style.Suffix;
254}
255
256static StyleKind findStyleKind(
257 const NamedDecl *D,
258 const std::vector<IdentifierNamingCheck::NamingStyle> &NamingStyles) {
259 if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef].isSet())
260 return SK_Typedef;
261
Alexander Kornienko5ae76e02016-06-07 09:11:19 +0000262 if (isa<TypeAliasDecl>(D) && NamingStyles[SK_TypeAlias].isSet())
263 return SK_TypeAlias;
264
Alexander Kornienko76c28802015-08-19 11:15:36 +0000265 if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) {
266 if (Decl->isAnonymousNamespace())
267 return SK_Invalid;
268
269 if (Decl->isInline() && NamingStyles[SK_InlineNamespace].isSet())
270 return SK_InlineNamespace;
271
272 if (NamingStyles[SK_Namespace].isSet())
273 return SK_Namespace;
274 }
275
276 if (isa<EnumDecl>(D) && NamingStyles[SK_Enum].isSet())
277 return SK_Enum;
278
279 if (isa<EnumConstantDecl>(D)) {
280 if (NamingStyles[SK_EnumConstant].isSet())
281 return SK_EnumConstant;
282
283 if (NamingStyles[SK_Constant].isSet())
284 return SK_Constant;
285
286 return SK_Invalid;
287 }
288
289 if (const auto *Decl = dyn_cast<CXXRecordDecl>(D)) {
290 if (Decl->isAnonymousStructOrUnion())
291 return SK_Invalid;
292
293 if (Decl->hasDefinition() && Decl->isAbstract() &&
294 NamingStyles[SK_AbstractClass].isSet())
295 return SK_AbstractClass;
296
297 if (Decl->isStruct() && NamingStyles[SK_Struct].isSet())
298 return SK_Struct;
299
300 if (Decl->isStruct() && NamingStyles[SK_Class].isSet())
301 return SK_Class;
302
303 if (Decl->isClass() && NamingStyles[SK_Class].isSet())
304 return SK_Class;
305
306 if (Decl->isClass() && NamingStyles[SK_Struct].isSet())
307 return SK_Struct;
308
309 if (Decl->isUnion() && NamingStyles[SK_Union].isSet())
310 return SK_Union;
311
312 if (Decl->isEnum() && NamingStyles[SK_Enum].isSet())
313 return SK_Enum;
314
315 return SK_Invalid;
316 }
317
318 if (const auto *Decl = dyn_cast<FieldDecl>(D)) {
319 QualType Type = Decl->getType();
320
321 if (!Type.isNull() && Type.isLocalConstQualified() &&
322 NamingStyles[SK_ConstantMember].isSet())
323 return SK_ConstantMember;
324
325 if (!Type.isNull() && Type.isLocalConstQualified() &&
326 NamingStyles[SK_Constant].isSet())
327 return SK_Constant;
328
329 if (Decl->getAccess() == AS_private &&
330 NamingStyles[SK_PrivateMember].isSet())
331 return SK_PrivateMember;
332
333 if (Decl->getAccess() == AS_protected &&
334 NamingStyles[SK_ProtectedMember].isSet())
335 return SK_ProtectedMember;
336
337 if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember].isSet())
338 return SK_PublicMember;
339
340 if (NamingStyles[SK_Member].isSet())
341 return SK_Member;
342
343 return SK_Invalid;
344 }
345
346 if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {
347 QualType Type = Decl->getType();
348
349 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable].isSet())
350 return SK_ConstexprVariable;
351
352 if (!Type.isNull() && Type.isLocalConstQualified() &&
353 NamingStyles[SK_ConstantParameter].isSet())
354 return SK_ConstantParameter;
355
356 if (!Type.isNull() && Type.isLocalConstQualified() &&
357 NamingStyles[SK_Constant].isSet())
358 return SK_Constant;
359
360 if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack].isSet())
361 return SK_ParameterPack;
362
363 if (NamingStyles[SK_Parameter].isSet())
364 return SK_Parameter;
365
366 return SK_Invalid;
367 }
368
369 if (const auto *Decl = dyn_cast<VarDecl>(D)) {
370 QualType Type = Decl->getType();
371
372 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable].isSet())
373 return SK_ConstexprVariable;
374
375 if (!Type.isNull() && Type.isLocalConstQualified() &&
376 Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant].isSet())
377 return SK_ClassConstant;
378
379 if (!Type.isNull() && Type.isLocalConstQualified() &&
380 Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant].isSet())
381 return SK_GlobalConstant;
382
383 if (!Type.isNull() && Type.isLocalConstQualified() &&
384 Decl->isStaticLocal() && NamingStyles[SK_StaticConstant].isSet())
385 return SK_StaticConstant;
386
387 if (!Type.isNull() && Type.isLocalConstQualified() &&
388 Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant].isSet())
389 return SK_LocalConstant;
390
391 if (!Type.isNull() && Type.isLocalConstQualified() &&
392 Decl->isFunctionOrMethodVarDecl() &&
393 NamingStyles[SK_LocalConstant].isSet())
394 return SK_LocalConstant;
395
396 if (!Type.isNull() && Type.isLocalConstQualified() &&
397 NamingStyles[SK_Constant].isSet())
398 return SK_Constant;
399
400 if (Decl->isStaticDataMember() && NamingStyles[SK_ClassMember].isSet())
401 return SK_ClassMember;
402
403 if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable].isSet())
404 return SK_GlobalVariable;
405
406 if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable].isSet())
407 return SK_StaticVariable;
408
409 if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable].isSet())
410 return SK_LocalVariable;
411
412 if (Decl->isFunctionOrMethodVarDecl() &&
413 NamingStyles[SK_LocalVariable].isSet())
414 return SK_LocalVariable;
415
416 if (NamingStyles[SK_Variable].isSet())
417 return SK_Variable;
418
419 return SK_Invalid;
420 }
421
422 if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {
423 if (Decl->isMain() || !Decl->isUserProvided() ||
424 Decl->isUsualDeallocationFunction() ||
425 Decl->isCopyAssignmentOperator() || Decl->isMoveAssignmentOperator() ||
426 Decl->size_overridden_methods() > 0)
427 return SK_Invalid;
428
429 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod].isSet())
430 return SK_ConstexprMethod;
431
432 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction].isSet())
433 return SK_ConstexprFunction;
434
435 if (Decl->isStatic() && NamingStyles[SK_ClassMethod].isSet())
436 return SK_ClassMethod;
437
438 if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod].isSet())
439 return SK_VirtualMethod;
440
441 if (Decl->getAccess() == AS_private &&
442 NamingStyles[SK_PrivateMethod].isSet())
443 return SK_PrivateMethod;
444
445 if (Decl->getAccess() == AS_protected &&
446 NamingStyles[SK_ProtectedMethod].isSet())
447 return SK_ProtectedMethod;
448
449 if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod].isSet())
450 return SK_PublicMethod;
451
452 if (NamingStyles[SK_Method].isSet())
453 return SK_Method;
454
455 if (NamingStyles[SK_Function].isSet())
456 return SK_Function;
457
458 return SK_Invalid;
459 }
460
461 if (const auto *Decl = dyn_cast<FunctionDecl>(D)) {
462 if (Decl->isMain())
463 return SK_Invalid;
464
465 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction].isSet())
466 return SK_ConstexprFunction;
467
468 if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction].isSet())
469 return SK_GlobalFunction;
470
471 if (NamingStyles[SK_Function].isSet())
472 return SK_Function;
473 }
474
475 if (isa<TemplateTypeParmDecl>(D)) {
476 if (NamingStyles[SK_TypeTemplateParameter].isSet())
477 return SK_TypeTemplateParameter;
478
479 if (NamingStyles[SK_TemplateParameter].isSet())
480 return SK_TemplateParameter;
481
482 return SK_Invalid;
483 }
484
485 if (isa<NonTypeTemplateParmDecl>(D)) {
486 if (NamingStyles[SK_ValueTemplateParameter].isSet())
487 return SK_ValueTemplateParameter;
488
489 if (NamingStyles[SK_TemplateParameter].isSet())
490 return SK_TemplateParameter;
491
492 return SK_Invalid;
493 }
494
495 if (isa<TemplateTemplateParmDecl>(D)) {
496 if (NamingStyles[SK_TemplateTemplateParameter].isSet())
497 return SK_TemplateTemplateParameter;
498
499 if (NamingStyles[SK_TemplateParameter].isSet())
500 return SK_TemplateParameter;
501
502 return SK_Invalid;
503 }
504
505 return SK_Invalid;
506}
507
Alexander Kornienko3d777682015-09-28 08:59:12 +0000508static void addUsage(IdentifierNamingCheck::NamingCheckFailureMap &Failures,
509 const NamedDecl *Decl, SourceRange Range,
510 const SourceManager *SM) {
Jonathan Coe2c8592a2016-01-26 18:55:55 +0000511 // Do nothing if the provided range is invalid.
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000512 if (Range.getBegin().isInvalid() || Range.getEnd().isInvalid())
513 return;
514
515 // Try to insert the identifier location in the Usages map, and bail out if it
516 // is already in there
Alexander Kornienko3d777682015-09-28 08:59:12 +0000517 auto &Failure = Failures[Decl];
518 if (!Failure.RawUsageLocs.insert(Range.getBegin().getRawEncoding()).second)
519 return;
520
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000521 Failure.ShouldFix = Failure.ShouldFix && !Range.getBegin().isMacroID() &&
Alexander Kornienko3d777682015-09-28 08:59:12 +0000522 !Range.getEnd().isMacroID();
523}
524
Alexander Kornienko76c28802015-08-19 11:15:36 +0000525void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) {
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000526 if (const auto *Decl =
527 Result.Nodes.getNodeAs<CXXConstructorDecl>("classRef")) {
528 if (Decl->isImplicit())
529 return;
530
531 addUsage(NamingCheckFailures, Decl->getParent(),
532 Decl->getNameInfo().getSourceRange(), Result.SourceManager);
533 return;
534 }
535
536 if (const auto *Decl =
537 Result.Nodes.getNodeAs<CXXDestructorDecl>("classRef")) {
538 if (Decl->isImplicit())
539 return;
540
541 SourceRange Range = Decl->getNameInfo().getSourceRange();
542 if (Range.getBegin().isInvalid())
543 return;
544 // The first token that will be found is the ~ (or the equivalent trigraph),
545 // we want instead to replace the next token, that will be the identifier.
546 Range.setBegin(CharSourceRange::getTokenRange(Range).getEnd());
547
548 addUsage(NamingCheckFailures, Decl->getParent(), Range,
549 Result.SourceManager);
550 return;
551 }
552
553 if (const auto *Loc = Result.Nodes.getNodeAs<TypeLoc>("typeLoc")) {
554 NamedDecl *Decl = nullptr;
555 if (const auto &Ref = Loc->getAs<TagTypeLoc>()) {
556 Decl = Ref.getDecl();
557 } else if (const auto &Ref = Loc->getAs<InjectedClassNameTypeLoc>()) {
558 Decl = Ref.getDecl();
559 } else if (const auto &Ref = Loc->getAs<UnresolvedUsingTypeLoc>()) {
560 Decl = Ref.getDecl();
561 } else if (const auto &Ref = Loc->getAs<TemplateTypeParmTypeLoc>()) {
562 Decl = Ref.getDecl();
563 }
564
565 if (Decl) {
566 addUsage(NamingCheckFailures, Decl, Loc->getSourceRange(),
567 Result.SourceManager);
568 return;
569 }
570
571 if (const auto &Ref = Loc->getAs<TemplateSpecializationTypeLoc>()) {
572 const auto *Decl =
573 Ref.getTypePtr()->getTemplateName().getAsTemplateDecl();
574
575 SourceRange Range(Ref.getTemplateNameLoc(), Ref.getTemplateNameLoc());
576 if (const auto *ClassDecl = dyn_cast<TemplateDecl>(Decl)) {
577 addUsage(NamingCheckFailures, ClassDecl->getTemplatedDecl(), Range,
578 Result.SourceManager);
579 return;
580 }
581 }
582
583 if (const auto &Ref =
584 Loc->getAs<DependentTemplateSpecializationTypeLoc>()) {
585 addUsage(NamingCheckFailures, Ref.getTypePtr()->getAsTagDecl(),
586 Loc->getSourceRange(), Result.SourceManager);
587 return;
588 }
589 }
590
591 if (const auto *Loc =
592 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>("nestedNameLoc")) {
593 if (NestedNameSpecifier *Spec = Loc->getNestedNameSpecifier()) {
594 if (NamespaceDecl *Decl = Spec->getAsNamespace()) {
595 addUsage(NamingCheckFailures, Decl, Loc->getLocalSourceRange(),
596 Result.SourceManager);
597 return;
598 }
599 }
600 }
601
602 if (const auto *Decl = Result.Nodes.getNodeAs<UsingDecl>("using")) {
603 for (const auto &Shadow : Decl->shadows()) {
604 addUsage(NamingCheckFailures, Shadow->getTargetDecl(),
605 Decl->getNameInfo().getSourceRange(), Result.SourceManager);
606 }
607 return;
608 }
609
610 if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declRef")) {
Alexander Kornienko76c28802015-08-19 11:15:36 +0000611 SourceRange Range = DeclRef->getNameInfo().getSourceRange();
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000612 addUsage(NamingCheckFailures, DeclRef->getDecl(), Range,
613 Result.SourceManager);
614 return;
Alexander Kornienko76c28802015-08-19 11:15:36 +0000615 }
616
617 if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
618 if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
619 return;
620
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000621 // Ignore ClassTemplateSpecializationDecl which are creating duplicate
622 // replacements with CXXRecordDecl
623 if (isa<ClassTemplateSpecializationDecl>(Decl))
624 return;
625
Alexander Kornienko76c28802015-08-19 11:15:36 +0000626 StyleKind SK = findStyleKind(Decl, NamingStyles);
627 if (SK == SK_Invalid)
628 return;
629
630 NamingStyle Style = NamingStyles[SK];
631 StringRef Name = Decl->getName();
632 if (matchesStyle(Name, Style))
633 return;
634
635 std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase);
636 std::replace(KindName.begin(), KindName.end(), '_', ' ');
637
638 std::string Fixup = fixupWithStyle(Name, Style);
639 if (StringRef(Fixup).equals(Name)) {
640 if (!IgnoreFailedSplit) {
Hans Wennborg53bd9f32016-02-29 21:17:39 +0000641 DEBUG(llvm::dbgs()
642 << Decl->getLocStart().printToString(*Result.SourceManager)
643 << llvm::format(": unable to split words for %s '%s'\n",
644 KindName.c_str(), Name));
Alexander Kornienko76c28802015-08-19 11:15:36 +0000645 }
646 } else {
647 NamingCheckFailure &Failure = NamingCheckFailures[Decl];
648 SourceRange Range =
649 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
650 .getSourceRange();
651
652 Failure.Fixup = std::move(Fixup);
653 Failure.KindName = std::move(KindName);
Alexander Kornienko3d777682015-09-28 08:59:12 +0000654 addUsage(NamingCheckFailures, Decl, Range, Result.SourceManager);
Alexander Kornienko76c28802015-08-19 11:15:36 +0000655 }
656 }
657}
658
659void IdentifierNamingCheck::onEndOfTranslationUnit() {
660 for (const auto &Pair : NamingCheckFailures) {
661 const NamedDecl &Decl = *Pair.first;
662 const NamingCheckFailure &Failure = Pair.second;
663
Alexander Kornienko3d777682015-09-28 08:59:12 +0000664 if (Failure.KindName.empty())
665 continue;
666
Alexander Kornienko76c28802015-08-19 11:15:36 +0000667 if (Failure.ShouldFix) {
Mike Aizatsky5b55df42015-12-04 20:57:03 +0000668 auto Diag = diag(Decl.getLocation(), "invalid case style for %0 '%1'")
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000669 << Failure.KindName << Decl.getName();
670
Alexander Kornienko3d777682015-09-28 08:59:12 +0000671 for (const auto &Loc : Failure.RawUsageLocs) {
672 // We assume that the identifier name is made of one token only. This is
673 // always the case as we ignore usages in macros that could build
674 // identifier names by combining multiple tokens.
Alexander Kornienko30c423b2015-10-01 09:19:40 +0000675 //
676 // For destructors, we alread take care of it by remembering the
677 // location of the start of the identifier and not the start of the
678 // tilde.
679 //
680 // Other multi-token identifiers, such as operators are not checked at
681 // all.
Alexander Kornienko76c28802015-08-19 11:15:36 +0000682 Diag << FixItHint::CreateReplacement(
Alexander Kornienko3d777682015-09-28 08:59:12 +0000683 SourceRange(SourceLocation::getFromRawEncoding(Loc)),
684 Failure.Fixup);
Alexander Kornienko76c28802015-08-19 11:15:36 +0000685 }
686 }
687 }
688}
689
690} // namespace readability
691} // namespace tidy
692} // namespace clang