244 lines · c
1//===----------------------------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H11 12#include "../utils/RenamerClangTidyCheck.h"13#include <optional>14#include <string>15namespace clang::tidy {16namespace readability {17 18enum 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` casing24/// 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 or27/// appended to the identifiers, regardless of the casing.28///29/// Many configuration options are available, in order to be able to create30/// different rules for different kind of identifier. In general, the31/// rules are falling back to a more generic rule if the specific case is not32/// configured.33class IdentifierNamingCheck final : public RenamerClangTidyCheck {34public:35 IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context);36 ~IdentifierNamingCheck() override;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_LeadingUpperSnakeCase49 };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 be84 // serialized85 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 {128 FileStyle() : IsActive(false), IgnoreMainLikeFunctions(false) {}129 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 136 ArrayRef<std::optional<NamingStyle>> getStyles() const {137 assert(IsActive);138 return Styles;139 }140 141 const HungarianNotationOption &getHNOption() const {142 assert(IsActive);143 return HNOption;144 }145 146 bool isActive() const { return IsActive; }147 bool isIgnoringMainLikeFunction() const { return IgnoreMainLikeFunctions; }148 149 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::FileStyle162 getFileStyleFromOptions(const ClangTidyCheck::OptionsView &Options) const;163 164 bool165 matchesStyle(StringRef Type, StringRef Name,166 const IdentifierNamingCheck::NamingStyle &Style,167 const IdentifierNamingCheck::HungarianNotationOption &HNOption,168 const NamedDecl *Decl) const;169 170 std::string171 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::string177 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 197private: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 StringRef getRealFileName(StringRef FileName) const;209 210 /// Find the style kind of a field in an anonymous record.211 StyleKind findStyleKindForAnonField(212 const FieldDecl *AnonField,213 ArrayRef<std::optional<NamingStyle>> NamingStyles) const;214 215 StyleKind findStyleKindForField(216 const FieldDecl *Field, QualType Type,217 ArrayRef<std::optional<NamingStyle>> NamingStyles) const;218 219 StyleKind220 findStyleKindForVar(const VarDecl *Var, QualType Type,221 ArrayRef<std::optional<NamingStyle>> NamingStyles) const;222 223 /// Stores the style options as a vector, indexed by the specified \ref224 /// StyleKind, for a given directory.225 mutable llvm::StringMap<FileStyle> NamingStylesCache;226 mutable llvm::StringMap<SmallString<256U>> RealFileNameCache;227 FileStyle *MainFileStyle;228 ClangTidyContext *Context;229 const bool GetConfigPerFile;230 const bool IgnoreFailedSplit;231 HungarianNotation HungarianNotation;232};233 234} // namespace readability235template <>236struct OptionEnumMapping<readability::IdentifierNamingCheck::CaseType> {237 static llvm::ArrayRef<238 std::pair<readability::IdentifierNamingCheck::CaseType, StringRef>>239 getEnumMapping();240};241} // namespace clang::tidy242 243#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H244