11 #include "clang/AST/CXXInheritance.h"
12 #include "clang/Lex/PPCallbacks.h"
13 #include "clang/Lex/Preprocessor.h"
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/DenseMapInfo.h"
16 #include "llvm/Support/Debug.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/Regex.h"
21 #define DEBUG_TYPE "clang-tidy"
31 std::pair<readability::IdentifierNamingCheck::CaseType, StringRef>>
37 {readability::IdentifierNamingCheck::CT_AnyCase,
"aNy_CasE"},
38 {readability::IdentifierNamingCheck::CT_LowerCase,
"lower_case"},
39 {readability::IdentifierNamingCheck::CT_UpperCase,
"UPPER_CASE"},
40 {readability::IdentifierNamingCheck::CT_CamelBack,
"camelBack"},
41 {readability::IdentifierNamingCheck::CT_CamelCase,
"CamelCase"},
42 {readability::IdentifierNamingCheck::CT_CamelSnakeCase,
44 {readability::IdentifierNamingCheck::CT_CamelSnakeBack,
46 return llvm::makeArrayRef(Mapping);
49 namespace readability {
52 #define NAMING_KEYS(m) \
56 m(ConstexprVariable) \
65 m(GlobalConstantPointer) \
69 m(LocalConstantPointer) \
76 m(ConstantParameter) \
80 m(ConstantPointerParameter) \
87 m(ConstexprFunction) \
97 m(TypeTemplateParameter) \
98 m(ValueTemplateParameter) \
99 m(TemplateTemplateParameter) \
100 m(TemplateParameter) \
106 #define ENUMERATE(v) SK_ ## v,
114 #define STRINGIZE(v) #v,
122 IdentifierNamingCheck::IdentifierNamingCheck(StringRef
Name,
125 IgnoreFailedSplit(Options.get(
"IgnoreFailedSplit", false)),
126 IgnoreMainLikeFunctions(Options.get(
"IgnoreMainLikeFunctions", false)) {
129 auto CaseOptional = [&]() -> llvm::Optional<CaseType> {
133 llvm::logAllUnhandledErrors(
136 return llvm::Error::success();
138 llvm::errs(),
"warning: ");
145 if (CaseOptional || !prefix.empty() || !postfix.empty()) {
146 NamingStyles.push_back(
NamingStyle(CaseOptional, prefix, postfix));
148 NamingStyles.push_back(llvm::None);
157 for (
size_t i = 0; i <
SK_Count; ++i) {
158 if (NamingStyles[i]) {
159 if (NamingStyles[i]->Case) {
161 *NamingStyles[i]->Case);
164 NamingStyles[i]->Prefix);
170 Options.
store(Opts,
"IgnoreFailedSplit", IgnoreFailedSplit);
171 Options.
store(Opts,
"IgnoreMainLikeFunctions", IgnoreMainLikeFunctions);
176 static llvm::Regex Matchers[] = {
178 llvm::Regex(
"^[a-z][a-z0-9_]*$"),
179 llvm::Regex(
"^[a-z][a-zA-Z0-9]*$"),
180 llvm::Regex(
"^[A-Z][A-Z0-9_]*$"),
181 llvm::Regex(
"^[A-Z][a-zA-Z0-9]*$"),
182 llvm::Regex(
"^[A-Z]([a-z0-9]*(_[A-Z])?)*"),
183 llvm::Regex(
"^[a-z]([a-z0-9]*(_[A-Z])?)*"),
186 if (
Name.startswith(Style.Prefix))
187 Name =
Name.drop_front(Style.Prefix.size());
191 if (
Name.endswith(Style.Suffix))
192 Name =
Name.drop_back(Style.Suffix.size());
198 if (
Name.startswith(
"_") ||
Name.endswith(
"_"))
201 if (Style.Case && !Matchers[static_cast<size_t>(*Style.Case)].match(
Name))
209 static llvm::Regex Splitter(
210 "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
212 SmallVector<StringRef, 8> Substrs;
213 Name.split(Substrs,
"_", -1,
false);
215 SmallVector<StringRef, 8> Words;
216 for (
auto Substr : Substrs) {
217 while (!Substr.empty()) {
218 SmallVector<StringRef, 8> Groups;
219 if (!Splitter.match(Substr, &Groups))
222 if (Groups[2].size() > 0) {
223 Words.push_back(Groups[1]);
224 Substr = Substr.substr(Groups[0].size());
225 }
else if (Groups[3].size() > 0) {
226 Words.push_back(Groups[3]);
227 Substr = Substr.substr(Groups[0].size() - Groups[4].size());
228 }
else if (Groups[5].size() > 0) {
229 Words.push_back(Groups[5]);
230 Substr = Substr.substr(Groups[0].size() - Groups[6].size());
236 return std::string(
Name);
245 for (
auto const &
Word : Words) {
246 if (&
Word != &Words.front())
248 Fixup +=
Word.lower();
253 for (
auto const &
Word : Words) {
254 if (&
Word != &Words.front())
256 Fixup +=
Word.upper();
261 for (
auto const &
Word : Words) {
262 Fixup +=
Word.substr(0, 1).upper();
263 Fixup +=
Word.substr(1).lower();
268 for (
auto const &
Word : Words) {
269 if (&
Word == &Words.front()) {
270 Fixup +=
Word.lower();
272 Fixup +=
Word.substr(0, 1).upper();
273 Fixup +=
Word.substr(1).lower();
279 for (
auto const &
Word : Words) {
280 if (&
Word != &Words.front())
282 Fixup +=
Word.substr(0, 1).upper();
283 Fixup +=
Word.substr(1).lower();
288 for (
auto const &
Word : Words) {
289 if (&
Word != &Words.front()) {
291 Fixup +=
Word.substr(0, 1).upper();
293 Fixup +=
Word.substr(0, 1).lower();
295 Fixup +=
Word.substr(1).lower();
304 bool IncludeMainLike) {
306 dyn_cast_or_null<FunctionDecl>(ParmDecl.getParentFunctionOrMethod());
311 if (!IncludeMainLike)
313 if (FDecl->getAccess() != AS_public && FDecl->getAccess() != AS_none)
315 enum MainType { None, Main, WMain };
316 auto IsCharPtrPtr = [](QualType QType) -> MainType {
319 if (QType = QType->getPointeeType(), QType.isNull())
321 if (QType = QType->getPointeeType(), QType.isNull())
323 if (QType->isCharType())
325 if (QType->isWideCharType())
329 auto IsIntType = [](QualType QType) {
332 if (
const auto *Builtin =
333 dyn_cast<BuiltinType>(QType->getUnqualifiedDesugaredType())) {
334 return Builtin->getKind() == BuiltinType::Int;
338 if (!IsIntType(FDecl->getReturnType()))
340 if (FDecl->getNumParams() < 2 || FDecl->getNumParams() > 3)
342 if (!IsIntType(FDecl->parameters()[0]->getType()))
344 MainType
Type = IsCharPtrPtr(FDecl->parameters()[1]->getType());
347 if (FDecl->getNumParams() == 3 &&
348 IsCharPtrPtr(FDecl->parameters()[2]->getType()) !=
Type)
352 static llvm::Regex Matcher(
353 "(^[Mm]ain([_A-Z]|$))|([a-z0-9_]Main([_A-Z]|$))|(_main(_|$))");
354 assert(Matcher.isValid() &&
"Invalid Matcher for main like functions.");
355 return Matcher.match(FDecl->getName());
357 static llvm::Regex Matcher(
"(^((W[Mm])|(wm))ain([_A-Z]|$))|([a-z0-9_]W[Mm]"
358 "ain([_A-Z]|$))|(_wmain(_|$))");
359 assert(Matcher.isValid() &&
"Invalid Matcher for wmain like functions.");
360 return Matcher.match(FDecl->getName());
368 Name, Style.Case.getValueOr(IdentifierNamingCheck::CaseType::CT_AnyCase));
369 StringRef Mid = StringRef(Fixed).trim(
"_");
372 return (Style.Prefix + Mid + Style.Suffix).str();
377 const std::vector<llvm::Optional<IdentifierNamingCheck::NamingStyle>>
379 bool IgnoreMainLikeFunctions) {
380 assert(D && D->getIdentifier() && !D->getName().empty() && !D->isImplicit() &&
381 "Decl must be an explicit identifier with a name.");
383 if (isa<ObjCIvarDecl>(D) && NamingStyles[SK_ObjcIvar])
386 if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef])
389 if (isa<TypeAliasDecl>(D) && NamingStyles[SK_TypeAlias])
392 if (
const auto *
Decl = dyn_cast<NamespaceDecl>(D)) {
393 if (
Decl->isAnonymousNamespace())
396 if (
Decl->isInline() && NamingStyles[SK_InlineNamespace])
397 return SK_InlineNamespace;
399 if (NamingStyles[SK_Namespace])
403 if (isa<EnumDecl>(D) && NamingStyles[SK_Enum])
406 if (isa<EnumConstantDecl>(D)) {
407 if (NamingStyles[SK_EnumConstant])
408 return SK_EnumConstant;
410 if (NamingStyles[SK_Constant])
416 if (
const auto *
Decl = dyn_cast<CXXRecordDecl>(D)) {
417 if (
Decl->isAnonymousStructOrUnion())
420 if (!
Decl->getCanonicalDecl()->isThisDeclarationADefinition())
423 if (
Decl->hasDefinition() &&
Decl->isAbstract() &&
424 NamingStyles[SK_AbstractClass])
425 return SK_AbstractClass;
427 if (
Decl->isStruct() && NamingStyles[SK_Struct])
430 if (
Decl->isStruct() && NamingStyles[SK_Class])
433 if (
Decl->isClass() && NamingStyles[SK_Class])
436 if (
Decl->isClass() && NamingStyles[SK_Struct])
439 if (
Decl->isUnion() && NamingStyles[SK_Union])
442 if (
Decl->isEnum() && NamingStyles[SK_Enum])
448 if (
const auto *
Decl = dyn_cast<FieldDecl>(D)) {
451 if (!
Type.isNull() &&
Type.isConstQualified()) {
452 if (NamingStyles[SK_ConstantMember])
453 return SK_ConstantMember;
455 if (NamingStyles[SK_Constant])
459 if (
Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMember])
460 return SK_PrivateMember;
462 if (
Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMember])
463 return SK_ProtectedMember;
465 if (
Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember])
466 return SK_PublicMember;
468 if (NamingStyles[SK_Member])
474 if (
const auto *
Decl = dyn_cast<ParmVarDecl>(D)) {
479 if (
Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])
480 return SK_ConstexprVariable;
482 if (!
Type.isNull() &&
Type.isConstQualified()) {
483 if (
Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_ConstantPointerParameter])
484 return SK_ConstantPointerParameter;
486 if (NamingStyles[SK_ConstantParameter])
487 return SK_ConstantParameter;
489 if (NamingStyles[SK_Constant])
493 if (
Decl->isParameterPack() && NamingStyles[SK_ParameterPack])
494 return SK_ParameterPack;
496 if (!
Type.isNull() &&
Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_PointerParameter])
497 return SK_PointerParameter;
499 if (NamingStyles[SK_Parameter])
505 if (
const auto *
Decl = dyn_cast<VarDecl>(D)) {
508 if (
Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable])
509 return SK_ConstexprVariable;
511 if (!
Type.isNull() &&
Type.isConstQualified()) {
512 if (
Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant])
513 return SK_ClassConstant;
515 if (
Decl->isFileVarDecl() &&
Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_GlobalConstantPointer])
516 return SK_GlobalConstantPointer;
518 if (
Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant])
519 return SK_GlobalConstant;
521 if (
Decl->isStaticLocal() && NamingStyles[SK_StaticConstant])
522 return SK_StaticConstant;
524 if (
Decl->isLocalVarDecl() &&
Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_LocalConstantPointer])
525 return SK_LocalConstantPointer;
527 if (
Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant])
528 return SK_LocalConstant;
530 if (
Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalConstant])
531 return SK_LocalConstant;
533 if (NamingStyles[SK_Constant])
537 if (
Decl->isStaticDataMember() && NamingStyles[SK_ClassMember])
538 return SK_ClassMember;
540 if (
Decl->isFileVarDecl() &&
Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_GlobalPointer])
541 return SK_GlobalPointer;
543 if (
Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable])
544 return SK_GlobalVariable;
546 if (
Decl->isStaticLocal() && NamingStyles[SK_StaticVariable])
547 return SK_StaticVariable;
549 if (
Decl->isLocalVarDecl() &&
Type.getTypePtr()->isAnyPointerType() && NamingStyles[SK_LocalPointer])
550 return SK_LocalPointer;
552 if (
Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable])
553 return SK_LocalVariable;
555 if (
Decl->isFunctionOrMethodVarDecl() && NamingStyles[SK_LocalVariable])
556 return SK_LocalVariable;
558 if (NamingStyles[SK_Variable])
564 if (
const auto *
Decl = dyn_cast<CXXMethodDecl>(D)) {
565 if (
Decl->isMain() || !
Decl->isUserProvided() ||
566 Decl->size_overridden_methods() > 0)
571 auto FindHidden = [&](
const CXXBaseSpecifier *S, clang::CXXBasePath &P) {
572 return CXXRecordDecl::FindOrdinaryMember(S, P,
Decl->getDeclName());
574 CXXBasePaths UnusedPaths;
575 if (
Decl->getParent()->lookupInBases(FindHidden, UnusedPaths))
578 if (
Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod])
579 return SK_ConstexprMethod;
581 if (
Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])
582 return SK_ConstexprFunction;
584 if (
Decl->isStatic() && NamingStyles[SK_ClassMethod])
585 return SK_ClassMethod;
587 if (
Decl->isVirtual() && NamingStyles[SK_VirtualMethod])
588 return SK_VirtualMethod;
590 if (
Decl->getAccess() == AS_private && NamingStyles[SK_PrivateMethod])
591 return SK_PrivateMethod;
593 if (
Decl->getAccess() == AS_protected && NamingStyles[SK_ProtectedMethod])
594 return SK_ProtectedMethod;
596 if (
Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod])
597 return SK_PublicMethod;
599 if (NamingStyles[SK_Method])
602 if (NamingStyles[SK_Function])
608 if (
const auto *
Decl = dyn_cast<FunctionDecl>(D)) {
612 if (
Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction])
613 return SK_ConstexprFunction;
615 if (
Decl->isGlobal() && NamingStyles[SK_GlobalFunction])
616 return SK_GlobalFunction;
618 if (NamingStyles[SK_Function])
622 if (isa<TemplateTypeParmDecl>(D)) {
623 if (NamingStyles[SK_TypeTemplateParameter])
624 return SK_TypeTemplateParameter;
626 if (NamingStyles[SK_TemplateParameter])
627 return SK_TemplateParameter;
632 if (isa<NonTypeTemplateParmDecl>(D)) {
633 if (NamingStyles[SK_ValueTemplateParameter])
634 return SK_ValueTemplateParameter;
636 if (NamingStyles[SK_TemplateParameter])
637 return SK_TemplateParameter;
642 if (isa<TemplateTemplateParmDecl>(D)) {
643 if (NamingStyles[SK_TemplateTemplateParameter])
644 return SK_TemplateTemplateParameter;
646 if (NamingStyles[SK_TemplateParameter])
647 return SK_TemplateParameter;
655 llvm::Optional<RenamerClangTidyCheck::FailureInfo>
656 IdentifierNamingCheck::GetDeclFailureInfo(
const NamedDecl *
Decl,
657 const SourceManager &SM)
const {
662 if (!NamingStyles[SK])
665 const NamingStyle &Style = *NamingStyles[SK];
671 std::replace(KindName.begin(), KindName.end(),
'_',
' ');
674 if (StringRef(Fixup).equals(
Name)) {
675 if (!IgnoreFailedSplit) {
676 LLVM_DEBUG(llvm::dbgs()
677 <<
Decl->getBeginLoc().printToString(SM)
678 << llvm::format(
": unable to split words for %s '%s'\n",
679 KindName.c_str(),
Name.str().c_str()));
683 return FailureInfo{std::move(KindName), std::move(Fixup)};
686 llvm::Optional<RenamerClangTidyCheck::FailureInfo>
687 IdentifierNamingCheck::GetMacroFailureInfo(
const Token &MacroNameTok,
688 const SourceManager &SM)
const {
689 if (!NamingStyles[SK_MacroDefinition])
692 StringRef
Name = MacroNameTok.getIdentifierInfo()->getName();
693 const NamingStyle &Style = *NamingStyles[SK_MacroDefinition];
697 std::string KindName =
699 std::replace(KindName.begin(), KindName.end(),
'_',
' ');
702 if (StringRef(Fixup).equals(
Name)) {
703 if (!IgnoreFailedSplit) {
704 LLVM_DEBUG(llvm::dbgs()
705 << MacroNameTok.getLocation().printToString(SM)
706 << llvm::format(
": unable to split words for %s '%s'\n",
707 KindName.c_str(),
Name.str().c_str()));
711 return FailureInfo{std::move(KindName), std::move(Fixup)};
714 RenamerClangTidyCheck::DiagInfo
715 IdentifierNamingCheck::GetDiagInfo(
const NamingCheckId &ID,
716 const NamingCheckFailure &Failure)
const {
717 return DiagInfo{
"invalid case style for %0 '%1'",
718 [&](DiagnosticBuilder &
diag) {
719 diag << Failure.Info.KindName << ID.second;