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 "llvm/ADT/Optional.h" 14 namespace clang { 15 namespace 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 }; 49 50 enum HungarianPrefixType { 51 HPT_Off = 0, 52 HPT_On, 53 HPT_LowerCase, 54 HPT_CamelCase, 55 }; 56 57 struct HungarianNotationOption { HungarianNotationOptionHungarianNotationOption58 HungarianNotationOption() : HPType(HungarianPrefixType::HPT_Off) {} 59 60 llvm::Optional<CaseType> Case; 61 HungarianPrefixType HPType; 62 llvm::StringMap<std::string> General; 63 llvm::StringMap<std::string> CString; 64 llvm::StringMap<std::string> PrimitiveType; 65 llvm::StringMap<std::string> UserDefinedType; 66 llvm::StringMap<std::string> DerivedType; 67 }; 68 69 struct NamingStyle { 70 NamingStyle() = default; 71 72 NamingStyle(llvm::Optional<CaseType> Case, const std::string &Prefix, 73 const std::string &Suffix, const std::string &IgnoredRegexpStr, 74 HungarianPrefixType HPType); 75 NamingStyle(const NamingStyle &O) = delete; 76 NamingStyle &operator=(NamingStyle &&O) = default; 77 NamingStyle(NamingStyle &&O) = default; 78 79 llvm::Optional<CaseType> Case; 80 std::string Prefix; 81 std::string Suffix; 82 // Store both compiled and non-compiled forms so original value can be 83 // serialized 84 llvm::Regex IgnoredRegexp; 85 std::string IgnoredRegexpStr; 86 87 HungarianPrefixType HPType; 88 }; 89 90 struct HungarianNotation { 91 public: 92 bool checkOptionValid(int StyleKindIndex) const; 93 bool isOptionEnabled(StringRef OptionKey, 94 const llvm::StringMap<std::string> &StrMap) const; 95 void loadDefaultConfig( 96 IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 97 void loadFileConfig( 98 const ClangTidyCheck::OptionsView &Options, 99 IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 100 101 bool removeDuplicatedPrefix( 102 SmallVector<StringRef, 8> &Words, 103 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 104 105 std::string getPrefix( 106 const Decl *D, 107 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 108 109 std::string getDataTypePrefix( 110 StringRef TypeName, const NamedDecl *ND, 111 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 112 113 std::string getClassPrefix( 114 const CXXRecordDecl *CRD, 115 const IdentifierNamingCheck::HungarianNotationOption &HNOption) const; 116 117 std::string getEnumPrefix(const EnumConstantDecl *ECD) const; 118 std::string getDeclTypeName(const NamedDecl *ND) const; 119 }; 120 121 struct FileStyle { FileStyleFileStyle122 FileStyle() : IsActive(false), IgnoreMainLikeFunctions(false) {} FileStyleFileStyle123 FileStyle(SmallVectorImpl<Optional<NamingStyle>> &&Styles, 124 HungarianNotationOption HNOption, bool IgnoreMainLike) 125 : Styles(std::move(Styles)), HNOption(std::move(HNOption)), 126 IsActive(true), IgnoreMainLikeFunctions(IgnoreMainLike) {} 127 getStylesFileStyle128 ArrayRef<Optional<NamingStyle>> getStyles() const { 129 assert(IsActive); 130 return Styles; 131 } 132 getHNOptionFileStyle133 const HungarianNotationOption &getHNOption() const { 134 assert(IsActive); 135 return HNOption; 136 } 137 isActiveFileStyle138 bool isActive() const { return IsActive; } isIgnoringMainLikeFunctionFileStyle139 bool isIgnoringMainLikeFunction() const { return IgnoreMainLikeFunctions; } 140 141 private: 142 SmallVector<Optional<NamingStyle>, 0> Styles; 143 HungarianNotationOption HNOption; 144 bool IsActive; 145 bool IgnoreMainLikeFunctions; 146 }; 147 148 IdentifierNamingCheck::FileStyle 149 getFileStyleFromOptions(const ClangTidyCheck::OptionsView &Options) const; 150 151 bool 152 matchesStyle(StringRef Type, StringRef Name, 153 const IdentifierNamingCheck::NamingStyle &Style, 154 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 155 const NamedDecl *Decl) const; 156 157 std::string 158 fixupWithCase(StringRef Type, StringRef Name, const Decl *D, 159 const IdentifierNamingCheck::NamingStyle &Style, 160 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 161 IdentifierNamingCheck::CaseType Case) const; 162 163 std::string 164 fixupWithStyle(StringRef Type, StringRef Name, 165 const IdentifierNamingCheck::NamingStyle &Style, 166 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 167 const Decl *D) const; 168 169 StyleKind findStyleKind( 170 const NamedDecl *D, 171 ArrayRef<llvm::Optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, 172 bool IgnoreMainLikeFunctions) const; 173 174 llvm::Optional<RenamerClangTidyCheck::FailureInfo> getFailureInfo( 175 StringRef Type, StringRef Name, const NamedDecl *ND, 176 SourceLocation Location, 177 ArrayRef<llvm::Optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, 178 const IdentifierNamingCheck::HungarianNotationOption &HNOption, 179 StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) const; 180 181 bool isParamInMainLikeFunction(const ParmVarDecl &ParmDecl, 182 bool IncludeMainLike) const; 183 184 private: 185 llvm::Optional<FailureInfo> 186 getDeclFailureInfo(const NamedDecl *Decl, 187 const SourceManager &SM) const override; 188 llvm::Optional<FailureInfo> 189 getMacroFailureInfo(const Token &MacroNameTok, 190 const SourceManager &SM) const override; 191 DiagInfo getDiagInfo(const NamingCheckId &ID, 192 const NamingCheckFailure &Failure) const override; 193 194 const FileStyle &getStyleForFile(StringRef FileName) const; 195 196 /// Stores the style options as a vector, indexed by the specified \ref 197 /// StyleKind, for a given directory. 198 mutable llvm::StringMap<FileStyle> NamingStylesCache; 199 FileStyle *MainFileStyle; 200 ClangTidyContext *Context; 201 const StringRef CheckName; 202 const bool GetConfigPerFile; 203 const bool IgnoreFailedSplit; 204 HungarianNotation HungarianNotation; 205 }; 206 207 } // namespace readability 208 template <> 209 struct OptionEnumMapping<readability::IdentifierNamingCheck::CaseType> { 210 static llvm::ArrayRef< 211 std::pair<readability::IdentifierNamingCheck::CaseType, StringRef>> 212 getEnumMapping(); 213 }; 214 } // namespace tidy 215 } // namespace clang 216 217 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H 218