[clang-tools-extra] r245429 - [clang-tidy] Add new IdentifierNaming check

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 19 04:15:37 PDT 2015


Author: alexfh
Date: Wed Aug 19 06:15:36 2015
New Revision: 245429

URL: http://llvm.org/viewvc/llvm-project?rev=245429&view=rev
Log:
[clang-tidy] Add new IdentifierNaming check

This check will try to enforce coding guidelines on the identifiers naming.
It supports lower_case, UPPER_CASE, camelBack and CamelCase casing and
tries to convert from one to another if a mismatch is detected.

It also supports a fixed prefix and suffix that will be prepended or appended
to the identifiers, regardless of the casing.

Many configuration options are available, in order to be able to create
different rules for different kind of identifier. In general, the
rules are falling back to a more generic rule if the specific case is not
configured.

http://reviews.llvm.org/D10933

Patch by Beren Minor!

Added:
    clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.cpp
    clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.h
    clang-tools-extra/trunk/test/clang-tidy/readability-identifier-naming.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp

Modified: clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt?rev=245429&r1=245428&r2=245429&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/readability/CMakeLists.txt Wed Aug 19 06:15:36 2015
@@ -5,6 +5,7 @@ add_clang_library(clangTidyReadabilityMo
   ContainerSizeEmptyCheck.cpp
   ElseAfterReturnCheck.cpp
   FunctionSizeCheck.cpp
+  IdentifierNamingCheck.cpp
   NamedParameterCheck.cpp
   NamespaceCommentCheck.cpp
   ReadabilityTidyModule.cpp

Added: clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.cpp?rev=245429&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.cpp Wed Aug 19 06:15:36 2015
@@ -0,0 +1,587 @@
+//===--- IdentifierNamingCheck.cpp - clang-tidy ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IdentifierNamingCheck.h"
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Format.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+#define DEBUG_TYPE "clang-tidy"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+#define NAMING_KEYS(m) \
+    m(Namespace) \
+    m(InlineNamespace) \
+    m(EnumConstant) \
+    m(ConstexprVariable) \
+    m(ConstantMember) \
+    m(PrivateMember) \
+    m(ProtectedMember) \
+    m(PublicMember) \
+    m(Member) \
+    m(ClassConstant) \
+    m(ClassMember) \
+    m(GlobalConstant) \
+    m(GlobalVariable) \
+    m(LocalConstant) \
+    m(LocalVariable) \
+    m(StaticConstant) \
+    m(StaticVariable) \
+    m(Constant) \
+    m(Variable) \
+    m(ConstantParameter) \
+    m(ParameterPack) \
+    m(Parameter) \
+    m(AbstractClass) \
+    m(Struct) \
+    m(Class) \
+    m(Union) \
+    m(Enum) \
+    m(GlobalFunction) \
+    m(ConstexprFunction) \
+    m(Function) \
+    m(ConstexprMethod) \
+    m(VirtualMethod) \
+    m(ClassMethod) \
+    m(PrivateMethod) \
+    m(ProtectedMethod) \
+    m(PublicMethod) \
+    m(Method) \
+    m(Typedef) \
+    m(TypeTemplateParameter) \
+    m(ValueTemplateParameter) \
+    m(TemplateTemplateParameter) \
+    m(TemplateParameter) \
+
+enum StyleKind {
+#define ENUMERATE(v) SK_ ## v,
+  NAMING_KEYS(ENUMERATE)
+#undef ENUMERATE
+  SK_Count,
+  SK_Invalid
+};
+
+static StringRef const StyleNames[] = {
+#define STRINGIZE(v) #v,
+  NAMING_KEYS(STRINGIZE)
+#undef STRINGIZE
+};
+
+#undef NAMING_KEYS
+
+IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name,
+                                             ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {
+  auto const fromString = [](StringRef Str) {
+    return llvm::StringSwitch<CaseType>(Str)
+        .Case("lower_case", CT_LowerCase)
+        .Case("UPPER_CASE", CT_UpperCase)
+        .Case("camelBack", CT_CamelBack)
+        .Case("CamelCase", CT_CamelCase)
+        .Default(CT_AnyCase);
+  };
+
+  for (auto const &Name : StyleNames) {
+    NamingStyles.push_back(
+        NamingStyle(fromString(Options.get((Name + "Case").str(), "")),
+                    Options.get((Name + "Prefix").str(), ""),
+                    Options.get((Name + "Suffix").str(), "")));
+  }
+
+  IgnoreFailedSplit = Options.get("IgnoreFailedSplit", 0);
+}
+
+void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  auto const toString = [](CaseType Type) {
+    switch (Type) {
+    case CT_AnyCase:
+      return "aNy_CasE";
+    case CT_LowerCase:
+      return "lower_case";
+    case CT_CamelBack:
+      return "camelBack";
+    case CT_UpperCase:
+      return "UPPER_CASE";
+    case CT_CamelCase:
+      return "CamelCase";
+    }
+
+    llvm_unreachable("Unknown Case Type");
+  };
+
+  for (size_t i = 0; i < SK_Count; ++i) {
+    Options.store(Opts, (StyleNames[i] + "Case").str(),
+                  toString(NamingStyles[i].Case));
+    Options.store(Opts, (StyleNames[i] + "Prefix").str(),
+                  NamingStyles[i].Prefix);
+    Options.store(Opts, (StyleNames[i] + "Suffix").str(),
+                  NamingStyles[i].Suffix);
+  }
+
+  Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
+}
+
+void IdentifierNamingCheck::registerMatchers(MatchFinder *Finder) {
+// FIXME: For now, only Decl and DeclRefExpr nodes are visited for checking and
+// replacement. There is a lot of missing cases, such as references to a class
+// name (as in 'const int CMyClass::kClassConstant = 4;'), to an enclosing
+// context (namespace, class, etc).
+
+  Finder->addMatcher(namedDecl().bind("decl"), this);
+  Finder->addMatcher(declRefExpr().bind("declref"), this);
+}
+
+static bool matchesStyle(StringRef Name,
+                         IdentifierNamingCheck::NamingStyle Style) {
+  static llvm::Regex Matchers[] = {
+      llvm::Regex("^.*$"),
+      llvm::Regex("^[a-z][a-z0-9_]*$"),
+      llvm::Regex("^[a-z][a-zA-Z0-9]*$"),
+      llvm::Regex("^[A-Z][A-Z0-9_]*$"),
+      llvm::Regex("^[A-Z][a-zA-Z0-9]*$"),
+  };
+
+  bool Matches = true;
+  if (Name.startswith(Style.Prefix))
+    Name = Name.drop_front(Style.Prefix.size());
+  else
+    Matches = false;
+
+  if (Name.endswith(Style.Suffix))
+    Name = Name.drop_back(Style.Suffix.size());
+  else
+    Matches = false;
+
+  if (!Matchers[static_cast<size_t>(Style.Case)].match(Name))
+    Matches = false;
+
+  return Matches;
+}
+
+static std::string fixupWithCase(StringRef Name,
+                                 IdentifierNamingCheck::CaseType Case) {
+  static llvm::Regex Splitter(
+      "([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$)");
+
+  SmallVector<StringRef, 8> Substrs;
+  Name.split(Substrs, "_", -1, false);
+
+  SmallVector<StringRef, 8> Words;
+  for (auto Substr : Substrs) {
+    while (!Substr.empty()) {
+      SmallVector<StringRef, 8> Groups;
+      if (!Splitter.match(Substr, &Groups))
+        break;
+
+      if (Groups[2].size() > 0) {
+        Words.push_back(Groups[1]);
+        Substr = Substr.substr(Groups[0].size());
+      } else if (Groups[3].size() > 0) {
+        Words.push_back(Groups[3]);
+        Substr = Substr.substr(Groups[0].size() - Groups[4].size());
+      } else if (Groups[5].size() > 0) {
+        Words.push_back(Groups[5]);
+        Substr = Substr.substr(Groups[0].size() - Groups[6].size());
+      }
+    }
+  }
+
+  if (Words.empty())
+    return Name;
+
+  std::string Fixup;
+  switch (Case) {
+  case IdentifierNamingCheck::CT_AnyCase:
+    Fixup += Name;
+    break;
+
+  case IdentifierNamingCheck::CT_LowerCase:
+    for (auto const &Word : Words) {
+      if (&Word != &Words.front())
+        Fixup += "_";
+      Fixup += Word.lower();
+    }
+    break;
+
+  case IdentifierNamingCheck::CT_UpperCase:
+    for (auto const &Word : Words) {
+      if (&Word != &Words.front())
+        Fixup += "_";
+      Fixup += Word.upper();
+    }
+    break;
+
+  case IdentifierNamingCheck::CT_CamelCase:
+    for (auto const &Word : Words) {
+      Fixup += Word.substr(0, 1).upper();
+      Fixup += Word.substr(1).lower();
+    }
+    break;
+
+  case IdentifierNamingCheck::CT_CamelBack:
+    for (auto const &Word : Words) {
+      if (&Word == &Words.front()) {
+        Fixup += Word.lower();
+      } else {
+        Fixup += Word.substr(0, 1).upper();
+        Fixup += Word.substr(1).lower();
+      }
+    }
+    break;
+  }
+
+  return Fixup;
+}
+
+static std::string fixupWithStyle(StringRef Name,
+                                  IdentifierNamingCheck::NamingStyle Style) {
+  return Style.Prefix + fixupWithCase(Name, Style.Case) + Style.Suffix;
+}
+
+static StyleKind findStyleKind(
+    const NamedDecl *D,
+    const std::vector<IdentifierNamingCheck::NamingStyle> &NamingStyles) {
+  if (isa<TypedefDecl>(D) && NamingStyles[SK_Typedef].isSet())
+    return SK_Typedef;
+
+  if (const auto *Decl = dyn_cast<NamespaceDecl>(D)) {
+    if (Decl->isAnonymousNamespace())
+      return SK_Invalid;
+
+    if (Decl->isInline() && NamingStyles[SK_InlineNamespace].isSet())
+      return SK_InlineNamespace;
+
+    if (NamingStyles[SK_Namespace].isSet())
+      return SK_Namespace;
+  }
+
+  if (isa<EnumDecl>(D) && NamingStyles[SK_Enum].isSet())
+    return SK_Enum;
+
+  if (isa<EnumConstantDecl>(D)) {
+    if (NamingStyles[SK_EnumConstant].isSet())
+      return SK_EnumConstant;
+
+    if (NamingStyles[SK_Constant].isSet())
+      return SK_Constant;
+
+    return SK_Invalid;
+  }
+
+  if (const auto *Decl = dyn_cast<CXXRecordDecl>(D)) {
+    if (Decl->isAnonymousStructOrUnion())
+      return SK_Invalid;
+
+    if (Decl->hasDefinition() && Decl->isAbstract() &&
+        NamingStyles[SK_AbstractClass].isSet())
+      return SK_AbstractClass;
+
+    if (Decl->isStruct() && NamingStyles[SK_Struct].isSet())
+      return SK_Struct;
+
+    if (Decl->isStruct() && NamingStyles[SK_Class].isSet())
+      return SK_Class;
+
+    if (Decl->isClass() && NamingStyles[SK_Class].isSet())
+      return SK_Class;
+
+    if (Decl->isClass() && NamingStyles[SK_Struct].isSet())
+      return SK_Struct;
+
+    if (Decl->isUnion() && NamingStyles[SK_Union].isSet())
+      return SK_Union;
+
+    if (Decl->isEnum() && NamingStyles[SK_Enum].isSet())
+      return SK_Enum;
+
+    return SK_Invalid;
+  }
+
+  if (const auto *Decl = dyn_cast<FieldDecl>(D)) {
+    QualType Type = Decl->getType();
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        NamingStyles[SK_ConstantMember].isSet())
+      return SK_ConstantMember;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        NamingStyles[SK_Constant].isSet())
+      return SK_Constant;
+
+    if (Decl->getAccess() == AS_private &&
+        NamingStyles[SK_PrivateMember].isSet())
+      return SK_PrivateMember;
+
+    if (Decl->getAccess() == AS_protected &&
+        NamingStyles[SK_ProtectedMember].isSet())
+      return SK_ProtectedMember;
+
+    if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMember].isSet())
+      return SK_PublicMember;
+
+    if (NamingStyles[SK_Member].isSet())
+      return SK_Member;
+
+    return SK_Invalid;
+  }
+
+  if (const auto *Decl = dyn_cast<ParmVarDecl>(D)) {
+    QualType Type = Decl->getType();
+
+    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable].isSet())
+      return SK_ConstexprVariable;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        NamingStyles[SK_ConstantParameter].isSet())
+      return SK_ConstantParameter;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        NamingStyles[SK_Constant].isSet())
+      return SK_Constant;
+
+    if (Decl->isParameterPack() && NamingStyles[SK_ParameterPack].isSet())
+      return SK_ParameterPack;
+
+    if (NamingStyles[SK_Parameter].isSet())
+      return SK_Parameter;
+
+    return SK_Invalid;
+  }
+
+  if (const auto *Decl = dyn_cast<VarDecl>(D)) {
+    QualType Type = Decl->getType();
+
+    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprVariable].isSet())
+      return SK_ConstexprVariable;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        Decl->isStaticDataMember() && NamingStyles[SK_ClassConstant].isSet())
+      return SK_ClassConstant;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        Decl->isFileVarDecl() && NamingStyles[SK_GlobalConstant].isSet())
+      return SK_GlobalConstant;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        Decl->isStaticLocal() && NamingStyles[SK_StaticConstant].isSet())
+      return SK_StaticConstant;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        Decl->isLocalVarDecl() && NamingStyles[SK_LocalConstant].isSet())
+      return SK_LocalConstant;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        Decl->isFunctionOrMethodVarDecl() &&
+        NamingStyles[SK_LocalConstant].isSet())
+      return SK_LocalConstant;
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        NamingStyles[SK_Constant].isSet())
+      return SK_Constant;
+
+    if (Decl->isStaticDataMember() && NamingStyles[SK_ClassMember].isSet())
+      return SK_ClassMember;
+
+    if (Decl->isFileVarDecl() && NamingStyles[SK_GlobalVariable].isSet())
+      return SK_GlobalVariable;
+
+    if (Decl->isStaticLocal() && NamingStyles[SK_StaticVariable].isSet())
+      return SK_StaticVariable;
+
+    if (Decl->isLocalVarDecl() && NamingStyles[SK_LocalVariable].isSet())
+      return SK_LocalVariable;
+
+    if (Decl->isFunctionOrMethodVarDecl() &&
+        NamingStyles[SK_LocalVariable].isSet())
+      return SK_LocalVariable;
+
+    if (NamingStyles[SK_Variable].isSet())
+      return SK_Variable;
+
+    return SK_Invalid;
+  }
+
+  if (const auto *Decl = dyn_cast<CXXMethodDecl>(D)) {
+    if (Decl->isMain() || !Decl->isUserProvided() ||
+        Decl->isUsualDeallocationFunction() ||
+        Decl->isCopyAssignmentOperator() || Decl->isMoveAssignmentOperator() ||
+        Decl->size_overridden_methods() > 0)
+      return SK_Invalid;
+
+    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod].isSet())
+      return SK_ConstexprMethod;
+
+    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction].isSet())
+      return SK_ConstexprFunction;
+
+    if (Decl->isStatic() && NamingStyles[SK_ClassMethod].isSet())
+      return SK_ClassMethod;
+
+    if (Decl->isVirtual() && NamingStyles[SK_VirtualMethod].isSet())
+      return SK_VirtualMethod;
+
+    if (Decl->getAccess() == AS_private &&
+        NamingStyles[SK_PrivateMethod].isSet())
+      return SK_PrivateMethod;
+
+    if (Decl->getAccess() == AS_protected &&
+        NamingStyles[SK_ProtectedMethod].isSet())
+      return SK_ProtectedMethod;
+
+    if (Decl->getAccess() == AS_public && NamingStyles[SK_PublicMethod].isSet())
+      return SK_PublicMethod;
+
+    if (NamingStyles[SK_Method].isSet())
+      return SK_Method;
+
+    if (NamingStyles[SK_Function].isSet())
+      return SK_Function;
+
+    return SK_Invalid;
+  }
+
+  if (const auto *Decl = dyn_cast<FunctionDecl>(D)) {
+    if (Decl->isMain())
+      return SK_Invalid;
+
+    if (Decl->isConstexpr() && NamingStyles[SK_ConstexprFunction].isSet())
+      return SK_ConstexprFunction;
+
+    if (Decl->isGlobal() && NamingStyles[SK_GlobalFunction].isSet())
+      return SK_GlobalFunction;
+
+    if (NamingStyles[SK_Function].isSet())
+      return SK_Function;
+  }
+
+  if (isa<TemplateTypeParmDecl>(D)) {
+    if (NamingStyles[SK_TypeTemplateParameter].isSet())
+      return SK_TypeTemplateParameter;
+
+    if (NamingStyles[SK_TemplateParameter].isSet())
+      return SK_TemplateParameter;
+
+    return SK_Invalid;
+  }
+
+  if (isa<NonTypeTemplateParmDecl>(D)) {
+    if (NamingStyles[SK_ValueTemplateParameter].isSet())
+      return SK_ValueTemplateParameter;
+
+    if (NamingStyles[SK_TemplateParameter].isSet())
+      return SK_TemplateParameter;
+
+    return SK_Invalid;
+  }
+
+  if (isa<TemplateTemplateParmDecl>(D)) {
+    if (NamingStyles[SK_TemplateTemplateParameter].isSet())
+      return SK_TemplateTemplateParameter;
+
+    if (NamingStyles[SK_TemplateParameter].isSet())
+      return SK_TemplateParameter;
+
+    return SK_Invalid;
+  }
+
+  return SK_Invalid;
+}
+
+void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declref")) {
+    auto It = NamingCheckFailures.find(DeclRef->getDecl());
+    if (It == NamingCheckFailures.end())
+      return;
+
+    NamingCheckFailure &Failure = It->second;
+    SourceRange Range = DeclRef->getNameInfo().getSourceRange();
+
+    Failure.Usages.push_back(Range);
+    Failure.ShouldFix = Failure.ShouldFix &&
+                        Result.SourceManager->isInMainFile(Range.getBegin()) &&
+                        Result.SourceManager->isInMainFile(Range.getEnd()) &&
+                        !Range.getBegin().isMacroID() &&
+                        !Range.getEnd().isMacroID();
+
+    return;
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
+    if (!Decl->getIdentifier() || Decl->getName().empty() || Decl->isImplicit())
+      return;
+
+    StyleKind SK = findStyleKind(Decl, NamingStyles);
+    if (SK == SK_Invalid)
+      return;
+
+    NamingStyle Style = NamingStyles[SK];
+    StringRef Name = Decl->getName();
+    if (matchesStyle(Name, Style))
+      return;
+
+    std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase);
+    std::replace(KindName.begin(), KindName.end(), '_', ' ');
+
+    std::string Fixup = fixupWithStyle(Name, Style);
+    if (StringRef(Fixup).equals(Name)) {
+      if (!IgnoreFailedSplit) {
+        DEBUG(llvm::dbgs() << Decl->getLocStart().printToString(
+                                  *Result.SourceManager)
+                           << format(": unable to split words for %s '%s'\n",
+                                     KindName.c_str(), Name));
+      }
+    } else {
+      NamingCheckFailure &Failure = NamingCheckFailures[Decl];
+      SourceRange Range =
+          DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation())
+              .getSourceRange();
+
+      Failure.Fixup = std::move(Fixup);
+      Failure.KindName = std::move(KindName);
+      Failure.ShouldFix =
+          Failure.ShouldFix &&
+          Result.SourceManager->isInMainFile(Range.getBegin()) &&
+          Result.SourceManager->isInMainFile(Range.getEnd()) &&
+          !Range.getBegin().isMacroID() && !Range.getEnd().isMacroID();
+    }
+  }
+}
+
+void IdentifierNamingCheck::onEndOfTranslationUnit() {
+  for (const auto &Pair : NamingCheckFailures) {
+    const NamedDecl &Decl = *Pair.first;
+    const NamingCheckFailure &Failure = Pair.second;
+
+    SourceRange DeclRange =
+        DeclarationNameInfo(Decl.getDeclName(), Decl.getLocation())
+            .getSourceRange();
+    auto Diag = diag(Decl.getLocStart(), "invalid case style for %0 '%1'")
+                << Failure.KindName << Decl.getName();
+
+    if (Failure.ShouldFix) {
+      Diag << FixItHint::CreateReplacement(
+          CharSourceRange::getTokenRange(DeclRange), Failure.Fixup);
+
+      for (const auto &Range : Failure.Usages) {
+        Diag << FixItHint::CreateReplacement(
+            CharSourceRange::getTokenRange(Range), Failure.Fixup);
+      }
+    }
+  }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.h?rev=245429&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/readability/IdentifierNamingCheck.h Wed Aug 19 06:15:36 2015
@@ -0,0 +1,73 @@
+//===--- IdentifierNamingCheck.h - clang-tidy -------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+/// \brief Checks for identifiers naming style mismatch.
+class IdentifierNamingCheck : public ClangTidyCheck {
+public:
+  IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context);
+
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void onEndOfTranslationUnit() override;
+
+  enum CaseType {
+    CT_AnyCase = 0,
+    CT_LowerCase,
+    CT_CamelBack,
+    CT_UpperCase,
+    CT_CamelCase,
+  };
+
+  struct NamingStyle {
+    NamingStyle() : Case(CT_AnyCase) {}
+
+    NamingStyle(CaseType Case, const std::string &Prefix,
+                const std::string &Suffix)
+        : Case(Case), Prefix(Prefix), Suffix(Suffix) {}
+
+    CaseType Case;
+    std::string Prefix;
+    std::string Suffix;
+
+    bool isSet() const {
+      return !(Case == CT_AnyCase && Prefix.empty() && Suffix.empty());
+    }
+  };
+
+private:
+  std::vector<NamingStyle> NamingStyles;
+  bool IgnoreFailedSplit;
+
+  struct NamingCheckFailure {
+    std::string KindName;
+    std::string Fixup;
+    bool ShouldFix;
+    std::vector<SourceRange> Usages;
+
+    NamingCheckFailure() : ShouldFix(true) {}
+  };
+
+  llvm::DenseMap<const NamedDecl *, NamingCheckFailure> NamingCheckFailures;
+};
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H

Modified: clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp?rev=245429&r1=245428&r2=245429&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/readability/ReadabilityTidyModule.cpp Wed Aug 19 06:15:36 2015
@@ -14,6 +14,7 @@
 #include "ContainerSizeEmptyCheck.h"
 #include "ElseAfterReturnCheck.h"
 #include "FunctionSizeCheck.h"
+#include "IdentifierNamingCheck.h"
 #include "NamedParameterCheck.h"
 #include "RedundantSmartptrGetCheck.h"
 #include "RedundantStringCStrCheck.h"
@@ -35,6 +36,8 @@ public:
         "readability-else-after-return");
     CheckFactories.registerCheck<FunctionSizeCheck>(
         "readability-function-size");
+    CheckFactories.registerCheck<IdentifierNamingCheck>(
+        "readability-identifier-naming");
     CheckFactories.registerCheck<readability::NamedParameterCheck>(
         "readability-named-parameter");
     CheckFactories.registerCheck<RedundantSmartptrGetCheck>(

Added: clang-tools-extra/trunk/test/clang-tidy/readability-identifier-naming.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/readability-identifier-naming.cpp?rev=245429&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/readability-identifier-naming.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/readability-identifier-naming.cpp Wed Aug 19 06:15:36 2015
@@ -0,0 +1,266 @@
+// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-identifier-naming %t \
+// RUN:   -config='{CheckOptions: [ \
+// RUN:     {key: readability-identifier-naming.AbstractClassCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.AbstractClassPrefix, value: 'A'}, \
+// RUN:     {key: readability-identifier-naming.ClassCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.ClassPrefix, value: 'C'}, \
+// RUN:     {key: readability-identifier-naming.ClassConstantCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.ClassConstantPrefix, value: 'k'}, \
+// RUN:     {key: readability-identifier-naming.ClassMemberCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.ClassMethodCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.ConstantCase, value: UPPER_CASE}, \
+// RUN:     {key: readability-identifier-naming.ConstantSuffix, value: '_CST'}, \
+// RUN:     {key: readability-identifier-naming.ConstexprFunctionCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.ConstexprMethodCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.ConstexprVariableCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.EnumCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.EnumPrefix, value: 'E'}, \
+// RUN:     {key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE}, \
+// RUN:     {key: readability-identifier-naming.FunctionCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE}, \
+// RUN:     {key: readability-identifier-naming.GlobalFunctionCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.GlobalVariableCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.GlobalVariablePrefix, value: 'g_'}, \
+// RUN:     {key: readability-identifier-naming.InlineNamespaceCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.LocalConstantCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.LocalConstantPrefix, value: 'k'}, \
+// RUN:     {key: readability-identifier-naming.LocalVariableCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.MemberCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.MemberPrefix, value: 'm_'}, \
+// RUN:     {key: readability-identifier-naming.ConstantMemberCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.PrivateMemberPrefix, value: '__'}, \
+// RUN:     {key: readability-identifier-naming.ProtectedMemberPrefix, value: '_'}, \
+// RUN:     {key: readability-identifier-naming.PublicMemberCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.MethodCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.PrivateMethodPrefix, value: '__'}, \
+// RUN:     {key: readability-identifier-naming.ProtectedMethodPrefix, value: '_'}, \
+// RUN:     {key: readability-identifier-naming.NamespaceCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.ParameterCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.ParameterPrefix, value: 'a_'}, \
+// RUN:     {key: readability-identifier-naming.ConstantParameterCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.ConstantParameterPrefix, value: 'i_'}, \
+// RUN:     {key: readability-identifier-naming.ParameterPackCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.PureFunctionCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.PureMethodCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE}, \
+// RUN:     {key: readability-identifier-naming.StaticVariableCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.StaticVariablePrefix, value: 's_'}, \
+// RUN:     {key: readability-identifier-naming.StructCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.TemplateParameterCase, value: UPPER_CASE}, \
+// RUN:     {key: readability-identifier-naming.TemplateTemplateParameterCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.TemplateUsingCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.TemplateUsingPrefix, value: 'u_'}, \
+// RUN:     {key: readability-identifier-naming.TypeTemplateParameterCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.TypeTemplateParameterSuffix, value: '_t'}, \
+// RUN:     {key: readability-identifier-naming.TypedefCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.TypedefSuffix, value: '_t'}, \
+// RUN:     {key: readability-identifier-naming.UnionCase, value: CamelCase}, \
+// RUN:     {key: readability-identifier-naming.UnionPrefix, value: 'U'}, \
+// RUN:     {key: readability-identifier-naming.UsingCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.ValueTemplateParameterCase, value: camelBack}, \
+// RUN:     {key: readability-identifier-naming.VariableCase, value: lower_case}, \
+// RUN:     {key: readability-identifier-naming.VirtualMethodCase, value: UPPER_CASE}, \
+// RUN:     {key: readability-identifier-naming.VirtualMethodPrefix, value: 'v_'}, \
+// RUN:     {key: readability-identifier-naming.IgnoreFailedSplit, value: 0} \
+// RUN:   ]}' -- -std=c++11
+// REQUIRES: shell
+
+// FIXME: There should be more test cases for checking that references to class
+// FIXME: name, declaration contexts, forward declarations, etc, are correctly
+// FIXME: checked and renamed
+
+namespace FOO_NS {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for namespace 'FOO_NS' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}namespace foo_ns {{{$}}
+inline namespace InlineNamespace {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for inline namespace 'InlineNamespace'
+// CHECK-FIXES: {{^}}inline namespace inline_namespace {{{$}}
+
+#define BLA int FOO_bar
+BLA;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global variable 'FOO_bar'
+// NO fix expected as FOO_bar is from macro expansion
+
+enum my_enumeration {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for enum 'my_enumeration'
+// CHECK-FIXES: {{^}}enum EMyEnumeration {{{$}}
+    MyConstant = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'MyConstant'
+// CHECK-FIXES: {{^}}    MY_CONSTANT = 1,{{$}}
+    your_CONST = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'your_CONST'
+// CHECK-FIXES: {{^}}    YOUR_CONST = 1,{{$}}
+    THIS_ConstValue = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'THIS_ConstValue'
+// CHECK-FIXES: {{^}}    THIS_CONST_VALUE = 1,{{$}}
+};
+
+constexpr int ConstExpr_variable = MyConstant;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for constexpr variable 'ConstExpr_variable'
+// CHECK-FIXES: {{^}}constexpr int const_expr_variable = MY_CONSTANT;{{$}}
+
+class my_class {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class 'my_class'
+// CHECK-FIXES: {{^}}class CMyClass {{{$}}
+    my_class();
+
+  const int MEMBER_one_1 = ConstExpr_variable;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: invalid case style for constant member 'MEMBER_one_1'
+// CHECK-FIXES: {{^}}  const int member_one_1 = const_expr_variable;{{$}}
+  int member2 = 2;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: invalid case style for private member 'member2'
+// CHECK-FIXES: {{^}}  int __member2 = 2;{{$}}
+
+private:
+    int private_member = 3;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for private member 'private_member'
+// CHECK-FIXES: {{^}}    int __private_member = 3;{{$}}
+
+protected:
+    int ProtMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for protected member 'ProtMember'
+// CHECK-FIXES: {{^}}    int _ProtMember;{{$}}
+
+public:
+    int PubMem;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for public member 'PubMem'
+// CHECK-FIXES: {{^}}    int pub_mem;{{$}}
+
+    static const int classConstant;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for class constant 'classConstant'
+// CHECK-FIXES: {{^}}    static const int kClassConstant;{{$}}
+    static int ClassMember_2;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for class member 'ClassMember_2'
+// CHECK-FIXES: {{^}}    static int ClassMember2;{{$}}
+};
+
+const int my_class::classConstant = 4;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class constant 'classConstant'
+// CHECK-FIXES: {{^}}const int my_class::kClassConstant = 4;{{$}}
+// FIXME: The fixup should reflect class name fixups as well:
+// FIXME: {{^}}const int CMyClass::kClassConstant = 4;{{$}}
+
+int my_class::ClassMember_2 = 5;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class member 'ClassMember_2'
+// CHECK-FIXES: {{^}}int my_class::ClassMember2 = 5;{{$}}
+// FIXME: The fixup should reflect class name fixups as well:
+// FIXME: {{^}}int CMyClass::ClassMember2 = 5;{{$}}
+
+const int global_Constant = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global constant 'global_Constant'
+// CHECK-FIXES: {{^}}const int GLOBAL_CONSTANT = 6;{{$}}
+int Global_variable = 7;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global variable 'Global_variable'
+// CHECK-FIXES: {{^}}int g_global_variable = 7;{{$}}
+
+void global_function(int PARAMETER_1, int const CONST_parameter) {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global function 'global_function'
+// CHECK-MESSAGES: :[[@LINE-2]]:22: warning: invalid case style for parameter 'PARAMETER_1'
+// CHECK-MESSAGES: :[[@LINE-3]]:39: warning: invalid case style for constant parameter 'CONST_parameter'
+// CHECK-FIXES: {{^}}void GlobalFunction(int a_parameter1, int const i_constParameter) {{{$}}
+    static const int THIS_static_ConsTant = 4;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for static constant 'THIS_static_ConsTant'
+// CHECK-FIXES: {{^}}    static const int THIS_STATIC_CONS_TANT = 4;{{$}}
+    static int THIS_static_variable;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for static variable 'THIS_static_variable'
+// CHECK-FIXES: {{^}}    static int s_thisStaticVariable;{{$}}
+    int const local_Constant = 3;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for local constant 'local_Constant'
+// CHECK-FIXES: {{^}}    int const kLocalConstant = 3;{{$}}
+    int LOCAL_VARIABLE;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for local variable 'LOCAL_VARIABLE'
+// CHECK-FIXES: {{^}}    int local_variable;{{$}}
+
+    int LOCAL_Array__[] = {0, 1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for local variable 'LOCAL_Array__'
+// CHECK-FIXES: {{^}}    int local_array[] = {0, 1, 2};{{$}}
+
+    for (auto _ : LOCAL_Array__) {
+    }
+}
+
+template<typename ... TYPE_parameters>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for type template parameter 'TYPE_parameters'
+// CHECK-FIXES: {{^}}template<typename ... typeParameters_t>{{$}}
+void Global_Fun(TYPE_parameters... PARAMETER_PACK) {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global function 'Global_Fun'
+// CHECK-MESSAGES: :[[@LINE-2]]:17: warning: invalid case style for parameter pack 'PARAMETER_PACK'
+// CHECK-FIXES: {{^}}void GlobalFun(TYPE_parameters... parameterPack) {{{$}}
+    global_function(1, 2);
+// CHECK-FIXES: {{^}}    GlobalFunction(1, 2);{{$}}
+    FOO_bar = Global_variable;
+// CHECK-FIXES: {{^}}    FOO_bar = g_global_variable;{{$}}
+// NO fix expected for FOO_bar declared in macro expansion
+}
+
+template<template<typename> class TPL_parameter, int COUNT_params, typename ... TYPE_parameters>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for template template parameter 'TPL_parameter'
+// CHECK-MESSAGES: :[[@LINE-2]]:50: warning: invalid case style for value template parameter 'COUNT_params'
+// CHECK-MESSAGES: :[[@LINE-3]]:68: warning: invalid case style for type template parameter 'TYPE_parameters'
+// CHECK-FIXES: {{^}}template<template<typename> class TplParameter, int countParams, typename ... typeParameters_t>{{$}}
+class test_CLASS {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class 'test_CLASS'
+// CHECK-FIXES: {{^}}class CTestClass {{{$}}
+};
+
+class abstract_class {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for abstract class 'abstract_class'
+// CHECK-FIXES: {{^}}class AAbstractClass {{{$}}
+    virtual ~abstract_class() = 0;
+    virtual void VIRTUAL_METHOD();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for virtual method 'VIRTUAL_METHOD'
+// CHECK-FIXES: {{^}}    virtual void v_VIRTUAL_METHOD();{{$}}
+    void non_Virtual_METHOD() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for private method 'non_Virtual_METHOD'
+// CHECK-FIXES: {{^}}    void __non_Virtual_METHOD() {}{{$}}
+    static void CLASS_METHOD() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for class method 'CLASS_METHOD'
+// CHECK-FIXES: {{^}}    static void classMethod() {}{{$}}
+
+    constexpr int CST_expr_Method() { return 2; }
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for constexpr method 'CST_expr_Method'
+// CHECK-FIXES: {{^}}    constexpr int cst_expr_method() { return 2; }{{$}}
+
+private:
+    void PRIVate_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for private method 'PRIVate_Method'
+// CHECK-FIXES: {{^}}    void __PRIVate_Method();{{$}}
+protected:
+    void protected_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for protected method 'protected_Method'
+// CHECK-FIXES: {{^}}    void _protected_Method();{{$}}
+public:
+    void public_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for method 'public_Method'
+// CHECK-FIXES: {{^}}    void publicMethod();{{$}}
+};
+
+constexpr int CE_function() { return 3; }
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for constexpr function 'CE_function'
+// CHECK-FIXES: {{^}}constexpr int ce_function() { return 3; }{{$}}
+
+struct THIS___Structure {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for struct 'THIS___Structure'
+// CHECK-FIXES: {{^}}struct this_structure {{{$}}
+    THIS___Structure();
+// FIXME: There should be a fixup for the constructor as well
+// FIXME: {{^}}    this_structure();{{$}}
+
+  union __MyUnion_is_wonderful__ {};
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: invalid case style for union '__MyUnion_is_wonderful__'
+// CHECK-FIXES: {{^}}  union UMyUnionIsWonderful {};{{$}}
+};
+
+typedef THIS___Structure struct_type;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for typedef 'struct_type'
+// CHECK-FIXES: {{^}}typedef THIS___Structure struct_type_t;{{$}}
+// FIXME: The fixup should reflect structure name fixups as well:
+// FIXME: {{^}}typedef this_structure struct_type_t;{{$}}
+
+static void static_Function() {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for function 'static_Function'
+// CHECK-FIXES: {{^}}static void staticFunction() {{{$}}
+}
+
+}
+}




More information about the cfe-commits mailing list