1 //===--- IdentifierNamingCheck.h - clang-tidy -------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H 11 12 #include "../utils/RenamerClangTidyCheck.h" 13 #include <optional> 14 #include <string> 15 namespace clang::tidy { 16 namespace readability { 17 18 enum StyleKind : int; 19 20 /// Checks for identifiers naming style mismatch. 21 /// 22 /// This check will try to enforce coding guidelines on the identifiers naming. 23 /// It supports `lower_case`, `UPPER_CASE`, `camelBack` and `CamelCase` casing 24 /// and tries to convert from one to another if a mismatch is detected. 25 /// 26 /// It also supports a fixed prefix and suffix that will be prepended or 27 /// appended to the identifiers, regardless of the casing. 28 /// 29 /// Many configuration options are available, in order to be able to create 30 /// different rules for different kind of identifier. In general, the 31 /// rules are falling back to a more generic rule if the specific case is not 32 /// configured. 33 class IdentifierNamingCheck final : public RenamerClangTidyCheck { 34 public: 35 IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context); 36 ~IdentifierNamingCheck(); 37 38 void storeOptions(ClangTidyOptions::OptionMap &Opts) override; 39 40 enum CaseType { 41 CT_AnyCase = 0, 42 CT_LowerCase, 43 CT_CamelBack, 44 CT_UpperCase, 45 CT_CamelCase, 46 CT_CamelSnakeCase, 47 CT_CamelSnakeBack, 48 CT_LeadingUpperSnakeCase 49 }; 50 51 enum HungarianPrefixType { 52 HPT_Off = 0, 53 HPT_On, 54 HPT_LowerCase, 55 HPT_CamelCase, 56 }; 57 58 struct HungarianNotationOption { 59 HungarianNotationOption() = default; 60 61 std::optional<CaseType> Case; 62 HungarianPrefixType HPType = HungarianPrefixType::HPT_Off; 63 llvm::StringMap<std::string> General; 64 llvm::StringMap<std::string> CString; 65 llvm::StringMap<std::string> PrimitiveType; 66 llvm::StringMap<std::string> UserDefinedType; 67 llvm::StringMap<std::string> DerivedType; 68 }; 69 70 struct NamingStyle { 71 NamingStyle() = default; 72 73 NamingStyle(std::optional<CaseType> Case, StringRef Prefix, 74 StringRef Suffix, StringRef IgnoredRegexpStr, 75 HungarianPrefixType HPType); 76 NamingStyle(const NamingStyle &O) = delete; 77 NamingStyle &operator=(NamingStyle &&O) = default; 78 NamingStyle(NamingStyle &&O) = default; 79 80 std::optional<CaseType> Case; 81 std::string Prefix; 82 std::string Suffix; 83 // Store both compiled and non-compiled forms so original value can be 84 // serialized 85 llvm::Regex IgnoredRegexp; 86 std::string IgnoredRegexpStr; 87 88 HungarianPrefixType HPType; 89 }; 90 91 struct HungarianNotation { 92 public: 93 bool checkOptionValid(int StyleKindIndex) const; 94 bool isOptionEnabled(StringRef OptionKey, 95 const llvm::StringMap<std::string> &StrMap) const; 96 97 size_t getAsteriskCount(const std::string &TypeName) const; 98 size_t getAsteriskCount(const std::string &TypeName, 99 const NamedDecl *ND) const; 100 101 void loadDefaultConfig( 102 IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 103 void loadFileConfig( 104 const ClangTidyCheck::OptionsView &Options, 105 IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 106 107 bool removeDuplicatedPrefix( 108 SmallVector<StringRef, 8> &Words, 109 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 110 111 std::string getPrefix( 112 const Decl *D, 113 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 114 115 std::string getDataTypePrefix( 116 StringRef TypeName, const NamedDecl *ND, 117 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 118 119 std::string getClassPrefix( 120 const CXXRecordDecl *CRD, 121 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 122 123 std::string getEnumPrefix(const EnumConstantDecl *ECD) const; 124 std::string getDeclTypeName(const NamedDecl *ND) const; 125 }; 126 127 struct FileStyle { FileStyleFileStyle128 FileStyle() : IsActive(false), IgnoreMainLikeFunctions(false) {} FileStyleFileStyle129 FileStyle(SmallVectorImpl<std::optional<NamingStyle>> &&Styles, 130 HungarianNotationOption HNOption, bool IgnoreMainLike, 131 bool CheckAnonFieldInParent) 132 : Styles(std::move(Styles)), HNOption(std::move(HNOption)), 133 IsActive(true), IgnoreMainLikeFunctions(IgnoreMainLike), 134 CheckAnonFieldInParentScope(CheckAnonFieldInParent) {} 135 getStylesFileStyle136 ArrayRef<std::optional<NamingStyle>> getStyles() const { 137 assert(IsActive); 138 return Styles; 139 } 140 getHNOptionFileStyle141 const HungarianNotationOption &getHNOption() const { 142 assert(IsActive); 143 return HNOption; 144 } 145 isActiveFileStyle146 bool isActive() const { return IsActive; } isIgnoringMainLikeFunctionFileStyle147 bool isIgnoringMainLikeFunction() const { return IgnoreMainLikeFunctions; } 148 isCheckingAnonFieldInParentScopeFileStyle149 bool isCheckingAnonFieldInParentScope() const { 150 return CheckAnonFieldInParentScope; 151 } 152 153 private: 154 SmallVector<std::optional<NamingStyle>, 0> Styles; 155 HungarianNotationOption HNOption; 156 bool IsActive; 157 bool IgnoreMainLikeFunctions; 158 bool CheckAnonFieldInParentScope; 159 }; 160 161 IdentifierNamingCheck::FileStyle 162 getFileStyleFromOptions(const ClangTidyCheck::OptionsView &Options) const; 163 164 bool 165 matchesStyle(StringRef Type, StringRef Name, 166 const IdentifierNamingCheck::NamingStyle &Style, 167 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 168 const NamedDecl *Decl) const; 169 170 std::string 171 fixupWithCase(StringRef Type, StringRef Name, const Decl *D, 172 const IdentifierNamingCheck::NamingStyle &Style, 173 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 174 IdentifierNamingCheck::CaseType Case) const; 175 176 std::string 177 fixupWithStyle(StringRef Type, StringRef Name, 178 const IdentifierNamingCheck::NamingStyle &Style, 179 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 180 const Decl *D) const; 181 182 StyleKind findStyleKind( 183 const NamedDecl *D, 184 ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, 185 bool IgnoreMainLikeFunctions, bool CheckAnonFieldInParentScope) const; 186 187 std::optional<RenamerClangTidyCheck::FailureInfo> getFailureInfo( 188 StringRef Type, StringRef Name, const NamedDecl *ND, 189 SourceLocation Location, 190 ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, 191 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 192 StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) const; 193 194 bool isParamInMainLikeFunction(const ParmVarDecl &ParmDecl, 195 bool IncludeMainLike) const; 196 197 private: 198 std::optional<FailureInfo> 199 getDeclFailureInfo(const NamedDecl *Decl, 200 const SourceManager &SM) const override; 201 std::optional<FailureInfo> 202 getMacroFailureInfo(const Token &MacroNameTok, 203 const SourceManager &SM) const override; 204 DiagInfo getDiagInfo(const NamingCheckId &ID, 205 const NamingCheckFailure &Failure) const override; 206 207 const FileStyle &getStyleForFile(StringRef FileName) const; 208 209 /// Find the style kind of a field in an anonymous record. 210 StyleKind findStyleKindForAnonField( 211 const FieldDecl *AnonField, 212 ArrayRef<std::optional<NamingStyle>> NamingStyles) const; 213 214 StyleKind findStyleKindForField( 215 const FieldDecl *Field, QualType Type, 216 ArrayRef<std::optional<NamingStyle>> NamingStyles) const; 217 218 StyleKind 219 findStyleKindForVar(const VarDecl *Var, QualType Type, 220 ArrayRef<std::optional<NamingStyle>> NamingStyles) const; 221 222 /// Stores the style options as a vector, indexed by the specified \ref 223 /// StyleKind, for a given directory. 224 mutable llvm::StringMap<FileStyle> NamingStylesCache; 225 FileStyle *MainFileStyle; 226 ClangTidyContext *Context; 227 const bool GetConfigPerFile; 228 const bool IgnoreFailedSplit; 229 HungarianNotation HungarianNotation; 230 }; 231 232 } // namespace readability 233 template <> 234 struct OptionEnumMapping<readability::IdentifierNamingCheck::CaseType> { 235 static llvm::ArrayRef< 236 std::pair<readability::IdentifierNamingCheck::CaseType, StringRef>> 237 getEnumMapping(); 238 }; 239 } // namespace clang::tidy 240 241 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H 242