berenm created this revision.
berenm added a reviewer: alexfh.
berenm added a subscriber: cfe-commits.

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

Files:
  clang-tidy/readability/CMakeLists.txt
  clang-tidy/readability/IdentifierNamingCheck.cpp
  clang-tidy/readability/IdentifierNamingCheck.h
  clang-tidy/readability/ReadabilityTidyModule.cpp
  test/clang-tidy/readability-identifier-naming.cpp

Index: test/clang-tidy/readability-identifier-naming.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/readability-identifier-naming.cpp
@@ -0,0 +1,197 @@
+// RUN: $(dirname %s)/check_clang_tidy.sh %s readability-identifier-naming %t -config='{CheckOptions: [{key: readability-identifier-naming.AbstractCase, value: CamelCase}, {key: readability-identifier-naming.AbstractPrefix, value: 'A'}, {key: readability-identifier-naming.ClassCase, value: CamelCase}, {key: readability-identifier-naming.ClassPrefix, value: 'C'}, {key: readability-identifier-naming.ClassConstantCase, value: CamelCase}, {key: readability-identifier-naming.ClassConstantPrefix, value: 'k'}, {key: readability-identifier-naming.ClassMemberCase, value: CamelCase}, {key: readability-identifier-naming.ClassMethodCase, value: camelBack}, {key: readability-identifier-naming.ConstantCase, value: UPPER_CASE}, {key: readability-identifier-naming.ConstantSuffix, value: '_CST'}, {key: readability-identifier-naming.ConstexprFunctionCase, value: lower_case}, {key: readability-identifier-naming.ConstexprMethodCase, value: lower_case}, {key: readability-identifier-naming.ConstexprVariableCase, value: lower_case}, {key: readability-identifier-naming.EnumCase, value: CamelCase}, {key: readability-identifier-naming.EnumPrefix, value: 'E'}, {key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE}, {key: readability-identifier-naming.FunctionCase, value: camelBack}, {key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE}, {key: readability-identifier-naming.GlobalFunctionCase, value: CamelCase}, {key: readability-identifier-naming.GlobalVariableCase, value: lower_case}, {key: readability-identifier-naming.GlobalVariablePrefix, value: 'g_'}, {key: readability-identifier-naming.InlineNamespaceCase, value: lower_case}, {key: readability-identifier-naming.LocalConstantCase, value: CamelCase}, {key: readability-identifier-naming.LocalConstantPrefix, value: 'k'}, {key: readability-identifier-naming.LocalVariableCase, value: lower_case}, {key: readability-identifier-naming.MemberCase, value: CamelCase}, {key: readability-identifier-naming.MemberPrefix, value: 'm_'}, {key: readability-identifier-naming.MemberConstantCase, value: lower_case}, {key: readability-identifier-naming.MemberPrivatePrefix, value: '__'}, {key: readability-identifier-naming.MemberProtectedPrefix, value: '_'}, {key: readability-identifier-naming.MemberPublicCase, value: lower_case}, {key: readability-identifier-naming.MethodCase, value: camelBack}, {key: readability-identifier-naming.MethodPrivatePrefix, value: '__'}, {key: readability-identifier-naming.MethodProtectedPrefix, value: '_'}, {key: readability-identifier-naming.NamespaceCase, value: lower_case}, {key: readability-identifier-naming.ParameterCase, value: camelBack}, {key: readability-identifier-naming.ParameterPrefix, value: 'a_'}, {key: readability-identifier-naming.ParameterConstantCase, value: camelBack}, {key: readability-identifier-naming.ParameterConstantPrefix, value: 'i_'}, {key: readability-identifier-naming.ParameterPackCase, value: camelBack}, {key: readability-identifier-naming.PureFunctionCase, value: lower_case}, {key: readability-identifier-naming.PureMethodCase, value: camelBack}, {key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE}, {key: readability-identifier-naming.StaticVariableCase, value: camelBack}, {key: readability-identifier-naming.StaticVariablePrefix, value: 's_'}, {key: readability-identifier-naming.StructCase, value: lower_case}, {key: readability-identifier-naming.TemplateParameterCase, value: UPPER_CASE}, {key: readability-identifier-naming.TemplateTemplateParameterCase, value: CamelCase}, {key: readability-identifier-naming.TemplateUsingCase, value: lower_case}, {key: readability-identifier-naming.TemplateUsingPrefix, value: 'u_'}, {key: readability-identifier-naming.TypeTemplateParameterCase, value: camelBack}, {key: readability-identifier-naming.TypeTemplateParameterSuffix, value: '_t'}, {key: readability-identifier-naming.TypedefCase, value: lower_case}, {key: readability-identifier-naming.TypedefSuffix, value: '_t'}, {key: readability-identifier-naming.UnionCase, value: CamelCase}, {key: readability-identifier-naming.UnionPrefix, value: 'U'}, {key: readability-identifier-naming.UsingCase, value: lower_case}, {key: readability-identifier-naming.ValueTemplateParameterCase, value: camelBack}, {key: readability-identifier-naming.VariableCase, value: lower_case}, {key: readability-identifier-naming.VirtualMethodCase, value: UPPER_CASE}, {key: readability-identifier-naming.VirtualMethodPrefix, value: 'v_'}, {key: readability-identifier-naming.IgnoreFailedSplit, value: 0}]}' -- -std=c++11
+// REQUIRES: shell
+
+namespace FOO_NS {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for namespace 'FOO_NS' [readability-identifier-naming]
+// CHECK-FIXES: foo_ns
+inline namespace InlineNamespace {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for inline namespace 'InlineNamespace' [readability-identifier-naming]
+// CHECK-FIXES: inline_namespace
+
+#define BLA int FOO_bar
+BLA;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global variable 'FOO_bar' [readability-identifier-naming]
+// 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' [readability-identifier-naming]
+// CHECK-FIXES: EMyEnumeration
+    MyConstant = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'MyConstant' [readability-identifier-naming]
+// CHECK-FIXES: MY_CONSTANT
+    your_CONST = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'your_CONST' [readability-identifier-naming]
+// CHECK-FIXES: YOUR_CONST
+    THIS_ConstValue = 1,
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for enum constant 'THIS_ConstValue' [readability-identifier-naming]
+// CHECK-FIXES: THIS_CONST_VALUE
+};
+
+constexpr int ConstExpr_variable = MyConstant;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for constexpr 'ConstExpr_variable' [readability-identifier-naming]
+// CHECK-FIXES: const_expr_variable
+// CHECK-FIXES: MY_CONSTANT
+
+class my_class {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class 'my_class' [readability-identifier-naming]
+// CHECK-FIXES: 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' [readability-identifier-naming]
+// CHECK-FIXES: member_one_1
+// CHECK-FIXES: const_expr_variable
+  int member2 = 2;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: invalid case style for private member 'member2' [readability-identifier-naming]
+// CHECK-FIXES: __member2
+
+private:
+    int private_member = 3;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for private member 'private_member' [readability-identifier-naming]
+// CHECK-FIXES: __private_member
+
+protected:
+    int ProtMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for protected member 'ProtMember' [readability-identifier-naming]
+// CHECK-FIXES: _ProtMember
+
+public:
+    int PubMem;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for public member 'PubMem' [readability-identifier-naming]
+// CHECK-FIXES: pub_mem
+
+    static const int classConstant;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for class constant 'classConstant' [readability-identifier-naming]
+// CHECK-FIXES: kClassConstant
+    static int ClassMember_2;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for class member 'ClassMember_2' [readability-identifier-naming]
+// CHECK-FIXES: ClassMember2
+};
+
+const int my_class::classConstant = 4;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class constant 'classConstant' [readability-identifier-naming]
+// CHECK-FIXES: kClassConstant
+int my_class::ClassMember_2 = 5;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class member 'ClassMember_2' [readability-identifier-naming]
+// CHECK-FIXES: ClassMember2
+
+const int global_Constant = 6;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global constant 'global_Constant' [readability-identifier-naming]
+// CHECK-FIXES: GLOBAL_CONSTANT
+int Global_variable = 7;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global variable 'Global_variable' [readability-identifier-naming]
+// CHECK-FIXES: g_global_variable
+
+void global_function(int PARAMETER_1, int const CONST_parameter) {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global function 'global_function' [readability-identifier-naming]
+// CHECK-FIXES: GlobalFunction
+// CHECK-MESSAGES: :[[@LINE-3]]:22: warning: invalid case style for parameter 'PARAMETER_1' [readability-identifier-naming]
+// CHECK-FIXES: a_parameter1
+// CHECK-MESSAGES: :[[@LINE-5]]:39: warning: invalid case style for constant parameter 'CONST_parameter' [readability-identifier-naming]
+// CHECK-FIXES: CONST_PARAMETER_CST
+    static const int THIS_static_ConsTant = 4;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for static constant 'THIS_static_ConsTant' [readability-identifier-naming]
+// CHECK-FIXES: THIS_STATIC_CONS_TANT
+    static int THIS_static_variable;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for static variable 'THIS_static_variable' [readability-identifier-naming]
+// CHECK-FIXES: s_thisStaticVariable
+    int const local_Constant = 3;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for local constant 'local_Constant' [readability-identifier-naming]
+// CHECK-FIXES: kLocalConstant
+    int LOCAL_VARIABLE;
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for local variable 'LOCAL_VARIABLE' [readability-identifier-naming]
+// CHECK-FIXES: local_variable
+
+    int LOCAL_Array__[] = {0, 1, 2};
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for local variable 'LOCAL_Array__' [readability-identifier-naming]
+// CHECK-FIXES: local_array
+
+    for (auto _ : LOCAL_Array__) {
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: unable to split words for local variable '_' [readability-identifier-naming]
+    }
+}
+
+template<typename ... TYPE_parameters>
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: invalid case style for type template parameter 'TYPE_parameters' [readability-identifier-naming]
+// CHECK-FIXES: typeParameters_t
+void Global_Fun(TYPE_parameters... PARAMETER_PACK) {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for global function 'Global_Fun' [readability-identifier-naming]
+// CHECK-FIXES: GlobalFun
+// CHECK-MESSAGES: :[[@LINE-3]]:17: warning: invalid case style for parameter pack 'PARAMETER_PACK' [readability-identifier-naming]
+// CHECK-FIXES: parameterPack
+    global_function(1, 2);
+// CHECK-FIXES: GlobalFunction
+    FOO_bar = Global_variable;
+// CHECK-FIXES: 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' [readability-identifier-naming]
+// CHECK-FIXES: TplParameter
+// CHECK-MESSAGES: :[[@LINE-3]]:50: warning: invalid case style for value template parameter 'COUNT_params' [readability-identifier-naming]
+// CHECK-FIXES: countParams
+// CHECK-MESSAGES: :[[@LINE-5]]:68: warning: invalid case style for type template parameter 'TYPE_parameters' [readability-identifier-naming]
+// CHECK-FIXES: typeParameters_t
+class test_CLASS {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for class 'test_CLASS' [readability-identifier-naming]
+// CHECK-FIXES: CTestClass
+};
+
+class abstract_class {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for abstract class 'abstract_class' [readability-identifier-naming]
+// CHECK-FIXES: AAbstractClass
+    virtual ~abstract_class() = 0;
+    virtual void VIRTUAL_METHOD();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for virtual method 'VIRTUAL_METHOD' [readability-identifier-naming]
+// CHECK-FIXES: v_VIRTUAL_METHOD
+    void non_Virtual_METHOD() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for private method 'non_Virtual_METHOD' [readability-identifier-naming]
+// CHECK-FIXES: __non_Virtual_METHOD
+    static void CLASS_METHOD() {}
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for class method 'CLASS_METHOD' [readability-identifier-naming]
+// CHECK-FIXES: classMethod
+
+    constexpr int CST_expr_Method() { return 2; }
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for constexpr method 'CST_expr_Method' [readability-identifier-naming]
+// CHECK-FIXES: cst_expr_method
+
+private:
+    void PRIVate_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for private method 'PRIVate_Method' [readability-identifier-naming]
+// CHECK-FIXES: __PRIVate_Method
+protected:
+    void protected_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for protected method 'protected_Method' [readability-identifier-naming]
+// CHECK-FIXES: _protected_Method
+public:
+    void public_Method();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: invalid case style for method 'public_Method' [readability-identifier-naming]
+// CHECK-FIXES: publicMethod
+};
+
+constexpr int CE_function() { return 3; }
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for constexpr function 'CE_function' [readability-identifier-naming]
+// CHECK-FIXES: ce_function
+
+struct THIS___Structure {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for struct 'THIS___Structure' [readability-identifier-naming]
+// CHECK-FIXES: this_structure
+    THIS___Structure();
+
+  union __MyUnion_is_wonderful__ {};
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: invalid case style for union '__MyUnion_is_wonderful__' [readability-identifier-naming]
+// CHECK-FIXES: UMyUnionIsWonderful
+};
+
+typedef THIS___Structure struct_type;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for typedef 'struct_type' [readability-identifier-naming]
+// CHECK-FIXES: struct_type_t
+
+static void static_Function() {
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: invalid case style for function 'static_Function' [readability-identifier-naming]
+// CHECK-FIXES: staticFunction
+}
+
+}
+}
Index: clang-tidy/readability/ReadabilityTidyModule.cpp
===================================================================
--- clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -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 @@
         "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>(
Index: clang-tidy/readability/IdentifierNamingCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/readability/IdentifierNamingCheck.h
@@ -0,0 +1,72 @@
+//===--- 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;
+
+private:
+  enum CaseType {
+    AnyCase = 0,
+    LowerCase,
+    CamelBack,
+    UpperCase,
+    CamelCase,
+  };
+
+  struct NamingStyle {
+    NamingStyle() : Case(CaseType::AnyCase) {}
+
+    NamingStyle(CaseType Case, std::string Prefix, std::string Suffix)
+        : Case(Case), Prefix(std::move(Prefix)), Suffix(std::move(Suffix)) {}
+
+    CaseType Case;
+    std::string Prefix;
+    std::string Suffix;
+
+    bool isSet() {
+      return !(Case == CaseType::AnyCase && Prefix.empty() && Suffix.empty());
+    }
+  };
+
+  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
Index: clang-tidy/readability/IdentifierNamingCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/readability/IdentifierNamingCheck.cpp
@@ -0,0 +1,627 @@
+//===--- 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 "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace readability {
+
+#define NAMING_KEYS(m) \
+    m(Namespace) \
+    m(InlineNamespace) \
+    m(EnumConstant) \
+    m(ConstexprVariable) \
+    m(MemberConstant) \
+    m(MemberPrivate) \
+    m(MemberProtected) \
+    m(MemberPublic) \
+    m(Member) \
+    m(ClassConstant) \
+    m(ClassMember) \
+    m(GlobalConstant) \
+    m(GlobalVariable) \
+    m(LocalConstant) \
+    m(LocalVariable) \
+    m(StaticConstant) \
+    m(StaticVariable) \
+    m(Constant) \
+    m(Variable) \
+    m(ParameterConstant) \
+    m(ParameterPack) \
+    m(Parameter) \
+    m(Abstract) \
+    m(Struct) \
+    m(Class) \
+    m(Union) \
+    m(Enum) \
+    m(GlobalFunction) \
+    m(ConstexprFunction) \
+    m(Function) \
+    m(ConstexprMethod) \
+    m(VirtualMethod) \
+    m(ClassMethod) \
+    m(MethodPrivate) \
+    m(MethodProtected) \
+    m(MethodPublic) \
+    m(Method) \
+    m(Typedef) \
+    m(TypeTemplateParameter) \
+    m(ValueTemplateParameter) \
+    m(TemplateTemplateParameter) \
+    m(TemplateParameter)
+
+enum StyleConst {
+#define ENUMERATE(v) v,
+  NAMING_KEYS(ENUMERATE)
+#undef ENUMERATE
+};
+
+static StyleConst const StyleKeys[] = {
+#define ENUMERATE(v) v,
+  NAMING_KEYS(ENUMERATE)
+#undef ENUMERATE
+};
+
+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) {
+    if (Str.equals("any") || Str.equals("aNy_CasE"))
+      return AnyCase;
+
+    if (Str.equals("lower") || Str.equals("lower_case"))
+      return LowerCase;
+
+    if (Str.equals("camelBack"))
+      return CamelBack;
+
+    if (Str.equals("upper") || Str.equals("UPPER_CASE"))
+      return UpperCase;
+
+    if (Str.equals("CamelCase"))
+      return CamelCase;
+
+    return AnyCase;
+  };
+
+  for (const auto &Key : StyleKeys) {
+    NamingStyles.push_back(NamingStyle(
+        fromString(Options.get((StyleNames[Key] + "Case").str(), "aNy_CasE")),
+        Options.get((StyleNames[Key] + "Prefix").str(), ""),
+        Options.get((StyleNames[Key] + "Suffix").str(), "")));
+  }
+
+  IgnoreFailedSplit = Options.get("IgnoreFailedSplit", 0);
+}
+
+void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  auto const toString = [](CaseType Type) {
+    switch (Type) {
+    default:
+    case AnyCase:
+      return "aNy_CasE";
+    case LowerCase:
+      return "lower_case";
+    case CamelBack:
+      return "camelBack";
+    case UpperCase:
+      return "UPPER_CASE";
+    case CamelCase:
+      return "CamelCase";
+    }
+  };
+
+  for (const auto &Key : StyleKeys) {
+    Options.store(Opts, (StyleNames[Key] + "Case").str(),
+                  toString(NamingStyles[Key].Case));
+    Options.store(Opts, (StyleNames[Key] + "Prefix").str(),
+                  NamingStyles[Key].Prefix);
+    Options.store(Opts, (StyleNames[Key] + "Suffix").str(),
+                  NamingStyles[Key].Suffix);
+  }
+
+  Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit);
+}
+
+void IdentifierNamingCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(namedDecl().bind("decl"), this);
+  Finder->addMatcher(declRefExpr().bind("declref"), this);
+}
+
+void IdentifierNamingCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *DeclRef = Result.Nodes.getNodeAs<DeclRefExpr>("declref")) {
+    auto It = NamingCheckFailures.find(cast<NamedDecl>(DeclRef->getDecl()));
+    if (It == NamingCheckFailures.end())
+        return;
+
+    auto &Failure = It->second;
+    auto 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;
+  }
+
+  auto KindName = "identifier";
+  auto Style = NamingStyle();
+
+  if (Result.Nodes.getNodeAs<TypedefDecl>("decl")) {
+    if (NamingStyles[Typedef].isSet()) {
+      KindName = "typedef";
+      Style = NamingStyles[Typedef];
+    }
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<NamespaceDecl>("decl")) {
+    if (Decl->isAnonymousNamespace())
+      return;
+
+    if (Decl->isInline() && NamingStyles[InlineNamespace].isSet()) {
+      KindName = "inline namespace";
+      Style = NamingStyles[InlineNamespace];
+
+    } else if (NamingStyles[Namespace].isSet()) {
+      KindName = "namespace";
+      Style = NamingStyles[Namespace];
+    }
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("decl")) {
+    if (Decl->isAnonymousStructOrUnion())
+      return;
+
+    if (Decl->hasDefinition() && Decl->isAbstract() &&
+        NamingStyles[Abstract].isSet()) {
+      KindName = "abstract class";
+      Style = NamingStyles[Abstract];
+
+    } else if (Decl->isStruct() && NamingStyles[Struct].isSet()) {
+      KindName = "struct";
+      Style = NamingStyles[Struct];
+
+    } else if (Decl->isStruct() && NamingStyles[Class].isSet()) {
+      KindName = "struct";
+      Style = NamingStyles[Class];
+
+    } else if (Decl->isClass() && NamingStyles[Class].isSet()) {
+      KindName = "class";
+      Style = NamingStyles[Class];
+
+    } else if (Decl->isClass() && NamingStyles[Struct].isSet()) {
+      KindName = "class";
+      Style = NamingStyles[Struct];
+
+    } else if (Decl->isUnion() && NamingStyles[Union].isSet()) {
+      KindName = "union";
+      Style = NamingStyles[Union];
+
+    } else if (Decl->isEnum() && NamingStyles[Enum].isSet()) {
+      KindName = "enum";
+      Style = NamingStyles[Enum];
+    }
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<FieldDecl>("decl")) {
+    auto Type = Decl->getType();
+
+    if (!Type.isNull() && Type.isLocalConstQualified() &&
+        NamingStyles[MemberConstant].isSet()) {
+      KindName = "constant member";
+      Style = NamingStyles[MemberConstant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               NamingStyles[Constant].isSet()) {
+      KindName = "constant member";
+      Style = NamingStyles[Constant];
+
+    } else if (Decl->getAccess() == clang::AS_private &&
+               NamingStyles[MemberPrivate].isSet()) {
+      KindName = "private member";
+      Style = NamingStyles[MemberPrivate];
+
+    } else if (Decl->getAccess() == clang::AS_protected &&
+               NamingStyles[MemberProtected].isSet()) {
+      KindName = "protected member";
+      Style = NamingStyles[MemberProtected];
+
+    } else if (Decl->getAccess() == clang::AS_public &&
+               NamingStyles[MemberPublic].isSet()) {
+      KindName = "public member";
+      Style = NamingStyles[MemberPublic];
+
+    } else if (NamingStyles[Member].isSet()) {
+      KindName = "member";
+      Style = NamingStyles[Member];
+    }
+
+  } else if (const auto *Decl = Result.Nodes.getNodeAs<ParmVarDecl>("decl")) {
+    auto Type = Decl->getType();
+
+    if (Decl->isConstexpr() && NamingStyles[ConstexprVariable].isSet()) {
+      KindName = "constexpr";
+      Style = NamingStyles[ConstexprVariable];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               NamingStyles[ParameterConstant].isSet()) {
+      KindName = "constant parameter";
+      Style = NamingStyles[Constant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               NamingStyles[Constant].isSet()) {
+      KindName = "constant parameter";
+      Style = NamingStyles[Constant];
+
+    } else if (Decl->isParameterPack() && NamingStyles[ParameterPack].isSet()) {
+      KindName = "parameter pack";
+      Style = NamingStyles[ParameterPack];
+
+    } else if (NamingStyles[Parameter].isSet()) {
+      KindName = "parameter";
+      Style = NamingStyles[Parameter];
+    }
+
+  } else if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("decl")) {
+    auto Type = Decl->getType();
+
+    if (Decl->isConstexpr() && NamingStyles[ConstexprVariable].isSet()) {
+      KindName = "constexpr";
+      Style = NamingStyles[ConstexprVariable];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               Decl->isStaticDataMember() &&
+               NamingStyles[ClassConstant].isSet()) {
+      KindName = "class constant";
+      Style = NamingStyles[ClassConstant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               Decl->isFileVarDecl() && NamingStyles[GlobalConstant].isSet()) {
+      KindName = "global constant";
+      Style = NamingStyles[GlobalConstant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               Decl->isStaticLocal() && NamingStyles[StaticConstant].isSet()) {
+      KindName = "static constant";
+      Style = NamingStyles[StaticConstant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               Decl->isLocalVarDecl() && NamingStyles[LocalConstant].isSet()) {
+      KindName = "local constant";
+      Style = NamingStyles[LocalConstant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               Decl->isFunctionOrMethodVarDecl() &&
+               NamingStyles[LocalConstant].isSet()) {
+      KindName = "local constant";
+      Style = NamingStyles[LocalConstant];
+
+    } else if (!Type.isNull() && Type.isLocalConstQualified() &&
+               NamingStyles[Constant].isSet()) {
+      KindName = "constant";
+      Style = NamingStyles[Constant];
+
+    } else if (Decl->isStaticDataMember() &&
+               NamingStyles[ClassMember].isSet()) {
+      KindName = "class member";
+      Style = NamingStyles[ClassMember];
+
+    } else if (Decl->isFileVarDecl() && NamingStyles[GlobalVariable].isSet()) {
+      KindName = "global variable";
+      Style = NamingStyles[GlobalVariable];
+
+    } else if (Decl->isStaticLocal() && NamingStyles[StaticVariable].isSet()) {
+      KindName = "static variable";
+      Style = NamingStyles[StaticVariable];
+
+    } else if (Decl->isLocalVarDecl() && NamingStyles[LocalVariable].isSet()) {
+      KindName = "local variable";
+      Style = NamingStyles[LocalVariable];
+
+    } else if (Decl->isFunctionOrMethodVarDecl() &&
+               NamingStyles[LocalVariable].isSet()) {
+      KindName = "local variable";
+      Style = NamingStyles[LocalVariable];
+
+    } else if (NamingStyles[Variable].isSet()) {
+      KindName = "variable";
+      Style = NamingStyles[Variable];
+    }
+  }
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl")) {
+    if (Decl->isMain() || !Decl->isUserProvided() ||
+        Decl->isUsualDeallocationFunction() ||
+        Decl->isCopyAssignmentOperator() || Decl->isMoveAssignmentOperator() ||
+        Decl->size_overridden_methods() > 0)
+      return;
+
+    if (Decl->isConstexpr() && NamingStyles[ConstexprMethod].isSet()) {
+      KindName = "constexpr method";
+      Style = NamingStyles[ConstexprMethod];
+
+    } else if (Decl->isConstexpr() && NamingStyles[ConstexprFunction].isSet()) {
+      KindName = "constexpr method";
+      Style = NamingStyles[ConstexprFunction];
+
+    } else if (Decl->isStatic() && NamingStyles[ClassMethod].isSet()) {
+      KindName = "class method";
+      Style = NamingStyles[ClassMethod];
+
+    } else if (Decl->isVirtual() && NamingStyles[VirtualMethod].isSet()) {
+      KindName = "virtual method";
+      Style = NamingStyles[VirtualMethod];
+
+    } else if (Decl->getAccess() == clang::AS_private &&
+               NamingStyles[MethodPrivate].isSet()) {
+      KindName = "private method";
+      Style = NamingStyles[MethodPrivate];
+
+    } else if (Decl->getAccess() == clang::AS_protected &&
+               NamingStyles[MethodProtected].isSet()) {
+      KindName = "protected method";
+      Style = NamingStyles[MethodProtected];
+
+    } else if (Decl->getAccess() == clang::AS_public &&
+               NamingStyles[MethodPublic].isSet()) {
+      KindName = "public method";
+      Style = NamingStyles[MethodPublic];
+
+    } else if (NamingStyles[Method].isSet()) {
+      KindName = "method";
+      Style = NamingStyles[Method];
+
+    } else if (NamingStyles[Function].isSet()) {
+      KindName = "method";
+      Style = NamingStyles[Function];
+    }
+
+  } else if (const auto *Decl = Result.Nodes.getNodeAs<FunctionDecl>("decl")) {
+    if (Decl->isMain())
+      return;
+
+    if (Decl->isConstexpr() && NamingStyles[ConstexprFunction].isSet()) {
+      KindName = "constexpr function";
+      Style = NamingStyles[ConstexprFunction];
+
+    } else if (Decl->isGlobal() && NamingStyles[GlobalFunction].isSet()) {
+      KindName = "global function";
+      Style = NamingStyles[GlobalFunction];
+
+    } else if (NamingStyles[Function].isSet()) {
+      KindName = "function";
+      Style = NamingStyles[Function];
+    }
+  }
+
+  if (Result.Nodes.getNodeAs<EnumDecl>("decl")) {
+    if (NamingStyles[Enum].isSet()) {
+      KindName = "enum";
+      Style = NamingStyles[Enum];
+    }
+  }
+
+  if (Result.Nodes.getNodeAs<EnumConstantDecl>("decl")) {
+    if (NamingStyles[EnumConstant].isSet()) {
+      KindName = "enum constant";
+      Style = NamingStyles[EnumConstant];
+
+    } else if (NamingStyles[Constant].isSet()) {
+      KindName = "enum constant";
+      Style = NamingStyles[Constant];
+    }
+  }
+
+  if (Result.Nodes.getNodeAs<TemplateTypeParmDecl>("decl")) {
+    if (NamingStyles[TypeTemplateParameter].isSet()) {
+      KindName = "type template parameter";
+      Style = NamingStyles[TypeTemplateParameter];
+
+    } else if (NamingStyles[TemplateParameter].isSet()) {
+      KindName = "template parameter";
+      Style = NamingStyles[TemplateParameter];
+    }
+
+  } else if (Result.Nodes.getNodeAs<NonTypeTemplateParmDecl>("decl")) {
+    if (NamingStyles[ValueTemplateParameter].isSet()) {
+      KindName = "value template parameter";
+      Style = NamingStyles[ValueTemplateParameter];
+
+    } else if (NamingStyles[TemplateParameter].isSet()) {
+      KindName = "template parameter";
+      Style = NamingStyles[TemplateParameter];
+    }
+
+  } else if (Result.Nodes.getNodeAs<TemplateTemplateParmDecl>("decl")) {
+    if (NamingStyles[TemplateTemplateParameter].isSet()) {
+      KindName = "template template parameter";
+      Style = NamingStyles[TemplateTemplateParameter];
+
+    } else if (NamingStyles[TemplateParameter].isSet()) {
+      KindName = "template parameter";
+      Style = NamingStyles[TemplateParameter];
+    }
+  }
+
+  if (!Style.isSet())
+    return;
+
+  auto matchesStyle = [](StringRef Name, NamingStyle Style) {
+    static llvm::Regex Matchers[] = {
+        llvm::Regex(StringRef("^.*$")),
+        llvm::Regex(StringRef("^[a-z][a-z0-9_]*$")),
+        llvm::Regex(StringRef("^[a-z][a-zA-Z0-9]*$")),
+        llvm::Regex(StringRef("^[A-Z][A-Z0-9_]*$")),
+        llvm::Regex(StringRef("^[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;
+  };
+
+  if (const auto *Decl = Result.Nodes.getNodeAs<NamedDecl>("decl")) {
+    if (matchesStyle(Decl->getName(), Style))
+      return;
+
+    auto fixupWithStyle = [](std::string Name, NamingStyle Style) {
+      static auto Splitter = llvm::Regex(StringRef(
+          "(([a-z0-9A-Z]*)(_+)|([A-Z]?[a-z0-9]+)([A-Z]|$)|([A-Z]+)([A-Z]|$))"));
+
+      auto Words = SmallVector<std::string, 8>();
+      auto Substrs = SmallVector<StringRef, 8>();
+      StringRef(Name).split(Substrs, "_", -1, false);
+      for (std::string Substr : Substrs) {
+        while (!Substr.empty()) {
+          auto Groups = SmallVector<StringRef, 8>();
+          if (!Splitter.match(Substr, &Groups))
+            break;
+
+          if (Groups[3].size() > 0) {
+            Words.emplace_back(std::move(Groups[2]));
+            Substr = Substr.substr(Groups[0].size());
+
+          } else if (Groups[4].size() > 0) {
+            Words.emplace_back(std::move(Groups[4]));
+            Substr = Substr.substr(Groups[0].size() - Groups[5].size());
+
+          } else if (Groups[6].size() > 0) {
+            Words.emplace_back(std::move(Groups[6]));
+            Substr = Substr.substr(Groups[0].size() - Groups[7].size());
+          }
+        }
+      }
+
+      if (Words.empty())
+        return Name;
+
+      std::string Fixup = Style.Prefix;
+      switch (Style.Case) {
+      case AnyCase:
+        Fixup += Name;
+        break;
+
+      case LowerCase:
+        for (auto const &Word : Words) {
+          if (&Word != &Words.front())
+            Fixup += "_";
+          Fixup += StringRef(Word).lower();
+        }
+        break;
+
+      case UpperCase:
+        for (auto const &Word : Words) {
+          if (&Word != &Words.front())
+            Fixup += "_";
+          Fixup += StringRef(Word).upper();
+        }
+        break;
+
+      case CamelCase:
+        for (auto const &Word : Words) {
+          Fixup += StringRef(Word).substr(0, 1).upper();
+          Fixup += StringRef(Word).substr(1).lower();
+        }
+        break;
+
+      case CamelBack:
+        for (auto const &Word : Words) {
+          if (&Word == &Words.front()) {
+            Fixup += StringRef(Word).lower();
+          } else {
+            Fixup += StringRef(Word).substr(0, 1).upper();
+            Fixup += StringRef(Word).substr(1).lower();
+          }
+        }
+        break;
+      }
+      Fixup += Style.Suffix;
+
+      return Fixup;
+    };
+
+    auto Name = Decl->getName();
+    auto Fixup = fixupWithStyle(Name, Style);
+    if (StringRef(Fixup).equals(Name)) {
+      if (!IgnoreFailedSplit) {
+        diag(Decl->getLocStart(), "unable to split words for %0 '%1'")
+            << KindName << Name;
+      }
+    } else {
+      auto &Failure = NamingCheckFailures[Decl];
+      auto Range =
+          clang::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 &P : NamingCheckFailures) {
+    auto DeclRange =
+        clang::DeclarationNameInfo(P.first->getDeclName(),
+                                   P.first->getLocation()).getSourceRange();
+    auto Diagn = diag(P.first->getLocStart(), "invalid case style for %0 '%1'")
+                 << P.second.KindName << P.first->getName();
+
+    if (P.second.ShouldFix) {
+      Diagn << FixItHint::CreateReplacement(
+          CharSourceRange::getTokenRange(DeclRange), P.second.Fixup);
+
+      for (const auto &Range : P.second.Usages) {
+        Diagn << FixItHint::CreateReplacement(
+            CharSourceRange::getTokenRange(Range), P.second.Fixup);
+      }
+    }
+  }
+}
+
+} // namespace readability
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/readability/CMakeLists.txt
===================================================================
--- clang-tidy/readability/CMakeLists.txt
+++ clang-tidy/readability/CMakeLists.txt
@@ -5,6 +5,7 @@
   ContainerSizeEmptyCheck.cpp
   ElseAfterReturnCheck.cpp
   FunctionSizeCheck.cpp
+  IdentifierNamingCheck.cpp
   NamedParameterCheck.cpp
   NamespaceCommentCheck.cpp
   ReadabilityTidyModule.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to