blob: 84fcb821de030bffd9bc0b2563f951e9f3771eaa [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
24#define NAMING_KEYS(m) \
25 m(Namespace) \
26 m(InlineNamespace) \
27 m(EnumConstant) \
28 m(ConstexprVariable) \
29 m(ConstantMember) \
30 m(PrivateMember) \
31 m(ProtectedMember) \
32 m(PublicMember) \
33 m(Member) \
34 m(ClassConstant) \
35 m(ClassMember) \
36 m(GlobalConstant) \
37 m(GlobalVariable) \
38 m(LocalConstant) \
39 m(LocalVariable) \
40 m(StaticConstant) \
41 m(StaticVariable) \
42 m(Constant) \
43 m(Variable) \
44 m(ConstantParameter) \
45 m(ParameterPack) \
46 m(Parameter) \
47 m(AbstractClass) \
48 m(Struct) \
49 m(Class) \
50 m(Union) \
51 m(Enum) \
52 m(GlobalFunction) \
53 m(ConstexprFunction) \
54 m(Function) \
55 m(ConstexprMethod) \
56 m(VirtualMethod) \
57 m(ClassMethod) \
58 m(PrivateMethod) \
59 m(ProtectedMethod) \
60 m(PublicMethod) \
61 m(Method) \
62 m(Typedef) \
63 m(TypeTemplateParameter) \
64 m(ValueTemplateParameter) \
65 m(TemplateTemplateParameter) \
66 m(TemplateParameter) \
67
68enum StyleKind {
69#define ENUMERATE(v) SK_ ## v,
70 NAMING_KEYS(ENUMERATE)
71#undef ENUMERATE
72 SK_Count,
73 SK_Invalid
74};
75
76static StringRef const StyleNames[] = {
77#define STRINGIZE(v) #v,
78 NAMING_KEYS(STRINGIZE)
79#undef STRINGIZE
80};
81
82#undef NAMING_KEYS
83
84IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,
85 ClangTidyContext *Context)
86 : ClangTidyCheck(Name, Context) {
87 auto const fromString = [](StringRef Str) {
88 return llvm::StringSwitch<CaseType>(Str)
89 .Case("lower_case", CT_LowerCase)
90 .Case("UPPER_CASE", CT_UpperCase)
91 .Case("camelBack", CT_CamelBack)
92 .Case("CamelCase", CT_CamelCase)
93 .Default(CT_AnyCase);
94 };
95
96 for (auto const &Name : StyleNames) {
97 NamingStyles.push_back(
98 NamingStyle(fromString(Options.get((Name + "Case").str(), "")),
99 Options.get((Name + "Prefix").str(), ""),
100 Options.get((Name + "Suffix").str(), "")));
101 }
102
103 IgnoreFailedSplit = Options.get("IgnoreFailedSplit", 0);
104}
105
106void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
107 auto const toString = [](CaseType Type) {
108 switch (Type) {
109 case CT_AnyCase:
110 return "aNy_CasE";
111 case CT_LowerCase:
112 return "lower_case";
113 case CT_CamelBack:
114 return "camelBack";
115 case CT_UpperCase:
116 return "UPPER_CASE";
117 case CT_CamelCase:
118 return "CamelCase";
119 }
120
121 llvm_unreachable("Unknown Case Type");
122 };
123
124 for (size_t i = 0; i < SK_Count; ++i) {
125 Options.store(Opts, (StyleNames[i] + "Case").str(),
126 toString(NamingStyles[i].Case));
127 Options.store(Opts, (StyleNames[i] + "Prefix").str(),
128 NamingStyles[i].Prefix);
129 Options.store(Opts, (StyleNames[i] + "Suffix").str(),
130 NamingStyles[i].Suffix);
131 }
132
133 Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
134}
135
136void IdentifierNamingCheck::registerMatchers(MatchFinder *Finder) {
137// FIXME: For now, only Decl and DeclRefExpr nodes are visited for checking and
138// replacement. There is a lot of missing cases, such as references to a class
139// name (as in 'const int CMyClass::kClassConstant = 4;'), to an enclosing
140// context (namespace, class, etc).
141
142 Finder->addMatcher(namedDecl().bind("decl"), this);
143 Finder->addMatcher(declRefExpr().bind("declref"), this);
144}
145
146static bool matchesStyle(StringRef Name,
147 IdentifierNamingCheck::NamingStyle Style) {
148 static llvm::Regex Matchers[] = {
149 llvm::Regex("^.*$"),
150 llvm::Regex("^[a-z][a-z0-9_]*$"),
151 llvm::Regex("^[a-z][a-zA-Z0-9]*$"),
152 llvm::Regex("^[A-Z][A-Z0-9_]*$"),
153 llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
154 };
155
156 bool Matches = true;
157 if (Name.startswith(Style.Prefix))
158 Name = Name.drop_front(Style.Prefix.size());
159 else
160 Matches = false;
161
162 if (Name.endswith(Style.Suffix))
163 Name = Name.drop_back(Style.Suffix.size());
164 else
165 Matches = false;
166
167 if (!Matchers[static_cast<size_t>(Style.Case)].match(Name))
168 Matches = false;
169
170 return Matches;
171}
172
173static std::string fixupWithCase(StringRef Name,
174 IdentifierNamingCheck::CaseType Case) {
175 static llvm::Regex Splitter(
176 "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
177
178 SmallVector<StringRef, 8> Substrs;
179 Name.split(Substrs, "_", -1, false);
180
181 SmallVector<StringRef, 8> Words;
182 for (auto Substr : Substrs) {
183 while (!Substr.empty()) {
184 SmallVector<StringRef, 8> Groups;
185 if (!Splitter.match(Substr, &Groups))
186 break;
187
188 if (Groups[2].size() > 0) {
189 Words.push_back(Groups[1]);
190 Substr = Substr.substr(Groups[0].size());
191 } else if (Groups[3].size() > 0) {
192 Words.push_back(Groups[3]);
193 Substr = Substr.substr(Groups[0].size() - Groups[4].size());
194 } else if (Groups[5].size() > 0) {
195 Words.push_back(Groups[5]);
196 Substr = Substr.substr(Groups[0].size() - Groups[6].size());
197 }
198 }
199 }
200
201 if (Words.empty())
202 return Name;
203
204 std::string Fixup;
205 switch (Case) {
206 case IdentifierNamingCheck::CT_AnyCase:
207 Fixup += Name;
208 break;
209
210 case IdentifierNamingCheck::CT_LowerCase:
211 for (auto const &Word : Words) {
212 if (&Word != &Words.front())
213 Fixup += "_";
214 Fixup += Word.lower();
215 }
216 break;
217
218 case IdentifierNamingCheck::CT_UpperCase:
219 for (auto const &Word : Words) {
220 if (&Word != &Words.front())
221 Fixup += "_";
222 Fixup += Word.upper();
223 }
224 break;
225
226 case IdentifierNamingCheck::CT_CamelCase:
227 for (auto const &Word : Words) {
228 Fixup += Word.substr(0, 1).upper();
229 Fixup += Word.substr(1).lower();
230 }
231 break;
232
233 case IdentifierNamingCheck::CT_CamelBack:
234 for (auto const &Word : Words) {
235 if (&Word == &Words.front()) {
236 Fixup += Word.lower();
237 } else {
238 Fixup += Word.substr(0, 1).upper();
239 Fixup += Word.substr(1).lower();
240 }
241 }
242 break;
243 }
244
245 return Fixup;
246}
247
248static std::string fixupWithStyle(StringRef Name,
249 IdentifierNamingCheck::NamingStyle Style) {
250 return Style.Prefix + fixupWithCase(Name, Style.Case) + Style.Suffix;
251}
252
253static StyleKind findStyleKind(
254 const NamedDecl *D,
255 const std::vector<IdentifierNamingCheck::NamingStyle> &NamingStyles) {
256 if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef].isSet())
257 return SK_Typedef;
258
259 if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) {
260 if (Decl->isAnonymousNamespace())
261 return SK_Invalid;
262
263 if (Decl->isInline() && NamingStyles[SK_InlineNamespace].isSet())
264 return SK_InlineNamespace;
265
266 if (NamingStyles[SK_Namespace].isSet())
267 return SK_Namespace;
268 }
269
270 if (isa<EnumDecl>(D) && NamingStyles[SK_Enum].isSet())
271 return SK_Enum;
272
273 if (isa<EnumConstantDecl>(D)) {
274 if (NamingStyles[SK_EnumConstant].isSet())
275 return SK_EnumConstant;
276
277 if (NamingStyles[SK_Constant].isSet())
278 return SK_Constant;
279
280 return SK_Invalid;
281 }
282
283 if (const auto *Decl = dyn_cast<CXXRecordDecl>(D)) {
284 if (Decl->isAnonymousStructOrUnion())
285 return SK_Invalid;
286
287 if (Decl->hasDefinition() && Decl->isAbstract() &&
288 NamingStyles[SK_AbstractClass].isSet())
289 return SK_AbstractClass;
290
291 if (Decl->isStruct() && NamingStyles[SK_Struct].isSet())
292 return SK_Struct;
293
294 if (Decl->isStruct() && NamingStyles[SK_Class].isSet())
295 return SK_Class;
296
297 if (Decl->isClass() && NamingStyles[SK_Class].isSet())
298 return SK_Class;
299
300 if (Decl->isClass() && NamingStyles[SK_Struct].isSet())
301 return SK_Struct;
302
303 if (Decl->isUnion() && NamingStyles[SK_Union].isSet())
304 return SK_Union;
305
306 if (Decl->isEnum() && NamingStyles[SK_Enum].isSet())
307 return SK_Enum;
308
309 return SK_Invalid;
310 }
311
312 if (const auto *Decl = dyn_cast<FieldDecl>(D)) {
313 QualType Type = Decl->getType();
314
315 if (!Type.isNull() && Type.isLocalConstQualified() &&
316 NamingStyles[SK_ConstantMember].isSet())
317 return SK_ConstantMember;
318
319 if (!Type.isNull() && Type.isLocalConstQualified() &&
320 NamingStyles[SK_Constant].isSet())
321 return SK_Constant;
322
323 if (Decl->getAccess() == AS_private &&
324 NamingStyles[SK_PrivateMember].isSet())
325 return SK_PrivateMember;
326
327 if (Decl->getAccess() == AS_protected &&
328 NamingStyles[SK_ProtectedMember].isSet())
329 return SK_ProtectedMember;
330
331 if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember].isSet())
332 return SK_PublicMember;
333
334 if (NamingStyles[SK_Member].isSet())
335 return SK_Member;
336
337 return SK_Invalid;
338 }
339
340 if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {
341 QualType Type = Decl->getType();
342
343 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable].isSet())
344 return SK_ConstexprVariable;
345
346 if (!Type.isNull() && Type.isLocalConstQualified() &&
347 NamingStyles[SK_ConstantParameter].isSet())
348 return SK_ConstantParameter;
349
350 if (!Type.isNull() && Type.isLocalConstQualified() &&
351 NamingStyles[SK_Constant].isSet())
352 return SK_Constant;
353
354 if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack].isSet())
355 return SK_ParameterPack;
356
357 if (NamingStyles[SK_Parameter].isSet())
358 return SK_Parameter;
359
360 return SK_Invalid;
361 }
362
363 if (const auto *Decl = dyn_cast<VarDecl>(D)) {
364 QualType Type = Decl->getType();
365
366 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable].isSet())
367 return SK_ConstexprVariable;
368
369 if (!Type.isNull() && Type.isLocalConstQualified() &&
370 Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant].isSet())
371 return SK_ClassConstant;
372
373 if (!Type.isNull() && Type.isLocalConstQualified() &&
374 Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant].isSet())
375 return SK_GlobalConstant;
376
377 if (!Type.isNull() && Type.isLocalConstQualified() &&
378 Decl->isStaticLocal() && NamingStyles[SK_StaticConstant].isSet())
379 return SK_StaticConstant;
380
381 if (!Type.isNull() && Type.isLocalConstQualified() &&
382 Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant].isSet())
383 return SK_LocalConstant;
384
385 if (!Type.isNull() && Type.isLocalConstQualified() &&
386 Decl->isFunctionOrMethodVarDecl() &&
387 NamingStyles[SK_LocalConstant].isSet())
388 return SK_LocalConstant;
389
390 if (!Type.isNull() && Type.isLocalConstQualified() &&
391 NamingStyles[SK_Constant].isSet())
392 return SK_Constant;
393
394 if (Decl->isStaticDataMember() && NamingStyles[SK_ClassMember].isSet())
395 return SK_ClassMember;
396
397 if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable].isSet())
398 return SK_GlobalVariable;
399
400 if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable].isSet())
401 return SK_StaticVariable;
402
403 if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable].isSet())
404 return SK_LocalVariable;
405
406 if (Decl->isFunctionOrMethodVarDecl() &&
407 NamingStyles[SK_LocalVariable].isSet())
408 return SK_LocalVariable;
409
410 if (NamingStyles[SK_Variable].isSet())
411 return SK_Variable;
412
413 return SK_Invalid;
414 }
415
416 if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {
417 if (Decl->isMain() || !Decl->isUserProvided() ||
418 Decl->isUsualDeallocationFunction() ||
419 Decl->isCopyAssignmentOperator() || Decl->isMoveAssignmentOperator() ||
420 Decl->size_overridden_methods() > 0)
421 return SK_Invalid;
422
423 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod].isSet())
424 return SK_ConstexprMethod;
425
426 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction].isSet())
427 return SK_ConstexprFunction;
428
429 if (Decl->isStatic() && NamingStyles[SK_ClassMethod].isSet())
430 return SK_ClassMethod;
431
432 if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod].isSet())
433 return SK_VirtualMethod;
434
435 if (Decl->getAccess() == AS_private &&
436 NamingStyles[SK_PrivateMethod].isSet())
437 return SK_PrivateMethod;
438
439 if (Decl->getAccess() == AS_protected &&
440 NamingStyles[SK_ProtectedMethod].isSet())
441 return SK_ProtectedMethod;
442
443 if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod].isSet())
444 return SK_PublicMethod;
445
446 if (NamingStyles[SK_Method].isSet())
447 return SK_Method;
448
449 if (NamingStyles[SK_Function].isSet())
450 return SK_Function;
451
452 return SK_Invalid;
453 }
454
455 if (const auto *Decl = dyn_cast<FunctionDecl>(D)) {
456 if (Decl->isMain())
457 return SK_Invalid;
458
459 if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction].isSet())
460 return SK_ConstexprFunction;
461
462 if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction].isSet())
463 return SK_GlobalFunction;
464
465 if (NamingStyles[SK_Function].isSet())
466 return SK_Function;
467 }
468
469 if (isa<TemplateTypeParmDecl>(D)) {
470 if (NamingStyles[SK_TypeTemplateParameter].isSet())
471 return SK_TypeTemplateParameter;
472
473 if (NamingStyles[SK_TemplateParameter].isSet())
474 return SK_TemplateParameter;
475
476 return SK_Invalid;
477 }
478
479 if (isa<NonTypeTemplateParmDecl>(D)) {
480 if (NamingStyles[SK_ValueTemplateParameter].isSet())
481 return SK_ValueTemplateParameter;
482
483 if (NamingStyles[SK_TemplateParameter].isSet())
484 return SK_TemplateParameter;
485
486 return SK_Invalid;
487 }
488
489 if (isa<TemplateTemplateParmDecl>(D)) {
490 if (NamingStyles[SK_TemplateTemplateParameter].isSet())
491 return SK_TemplateTemplateParameter;
492
493 if (NamingStyles[SK_TemplateParameter].isSet())
494 return SK_TemplateParameter;
495
496 return SK_Invalid;
497 }
498
499 return SK_Invalid;
500}
501
502void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) {
503 if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declref")) {
504 auto It = NamingCheckFailures.find(DeclRef->getDecl());
505 if (It == NamingCheckFailures.end())
506 return;
507
508 NamingCheckFailure &Failure = It->second;
509 SourceRange Range = DeclRef->getNameInfo().getSourceRange();
510
511 Failure.Usages.push_back(Range);
512 Failure.ShouldFix = Failure.ShouldFix &&
513 Result.SourceManager->isInMainFile(Range.getBegin()) &&
514 Result.SourceManager->isInMainFile(Range.getEnd()) &&
515 !Range.getBegin().isMacroID() &&
516 !Range.getEnd().isMacroID();
517
518 return;
519 }
520
521 if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
522 if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
523 return;
524
525 StyleKind SK = findStyleKind(Decl, NamingStyles);
526 if (SK == SK_Invalid)
527 return;
528
529 NamingStyle Style = NamingStyles[SK];
530 StringRef Name = Decl->getName();
531 if (matchesStyle(Name, Style))
532 return;
533
534 std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase);
535 std::replace(KindName.begin(), KindName.end(), '_', ' ');
536
537 std::string Fixup = fixupWithStyle(Name, Style);
538 if (StringRef(Fixup).equals(Name)) {
539 if (!IgnoreFailedSplit) {
540 DEBUG(llvm::dbgs() << Decl->getLocStart().printToString(
541 *Result.SourceManager)
542 << format(": unable to split words for %s '%s'\n",
543 KindName.c_str(), Name));
544 }
545 } else {
546 NamingCheckFailure &Failure = NamingCheckFailures[Decl];
547 SourceRange Range =
548 DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
549 .getSourceRange();
550
551 Failure.Fixup = std::move(Fixup);
552 Failure.KindName = std::move(KindName);
553 Failure.ShouldFix =
554 Failure.ShouldFix &&
555 Result.SourceManager->isInMainFile(Range.getBegin()) &&
556 Result.SourceManager->isInMainFile(Range.getEnd()) &&
557 !Range.getBegin().isMacroID() && !Range.getEnd().isMacroID();
558 }
559 }
560}
561
562void IdentifierNamingCheck::onEndOfTranslationUnit() {
563 for (const auto &Pair : NamingCheckFailures) {
564 const NamedDecl &Decl = *Pair.first;
565 const NamingCheckFailure &Failure = Pair.second;
566
567 SourceRange DeclRange =
568 DeclarationNameInfo(Decl.getDeclName(), Decl.getLocation())
569 .getSourceRange();
570 auto Diag = diag(Decl.getLocStart(), "invalid case style for %0 '%1'")
571 << Failure.KindName << Decl.getName();
572
573 if (Failure.ShouldFix) {
574 Diag << FixItHint::CreateReplacement(
575 CharSourceRange::getTokenRange(DeclRange), Failure.Fixup);
576
577 for (const auto &Range : Failure.Usages) {
578 Diag << FixItHint::CreateReplacement(
579 CharSourceRange::getTokenRange(Range), Failure.Fixup);
580 }
581 }
582 }
583}
584
585} // namespace readability
586} // namespace tidy
587} // namespace clang