1 //===--- RenamerClangTidyCheck.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_RENAMERCLANGTIDYCHECK_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H 11 12 #include "../ClangTidyCheck.h" 13 #include "llvm/ADT/DenseMap.h" 14 #include "llvm/ADT/DenseSet.h" 15 #include "llvm/ADT/FunctionExtras.h" 16 #include <optional> 17 #include <string> 18 #include <utility> 19 20 namespace clang { 21 22 class MacroInfo; 23 24 namespace tidy { 25 26 /// Base class for clang-tidy checks that want to flag declarations and/or 27 /// macros for renaming based on customizable criteria. 28 class RenamerClangTidyCheck : public ClangTidyCheck { 29 public: 30 RenamerClangTidyCheck(StringRef CheckName, ClangTidyContext *Context); 31 ~RenamerClangTidyCheck(); 32 33 /// Derived classes should not implement any matching logic themselves; this 34 /// class will do the matching and call the derived class' 35 /// getDeclFailureInfo() and getMacroFailureInfo() for determining whether a 36 /// given identifier passes or fails the check. 37 void registerMatchers(ast_matchers::MatchFinder *Finder) final; 38 void check(const ast_matchers::MatchFinder::MatchResult &Result) final; 39 void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, 40 Preprocessor *ModuleExpanderPP) final; 41 void onEndOfTranslationUnit() final; 42 43 /// Derived classes that override this function should call this method from 44 /// the overridden method. 45 void storeOptions(ClangTidyOptions::OptionMap &Opts) override; 46 47 /// This enum will be used in %select of the diagnostic message. 48 /// Each value below IgnoreFailureThreshold should have an error message. 49 enum class ShouldFixStatus { 50 ShouldFix, 51 52 /// The fixup will conflict with a language keyword, 53 /// so we can't fix it automatically. 54 ConflictsWithKeyword, 55 56 /// The fixup will conflict with a macro 57 /// definition, so we can't fix it 58 /// automatically. 59 ConflictsWithMacroDefinition, 60 61 /// The fixup results in an identifier that is not a valid c/c++ identifier. 62 FixInvalidIdentifier, 63 64 /// Values pass this threshold will be ignored completely 65 /// i.e no message, no fixup. 66 IgnoreFailureThreshold, 67 68 /// If the identifier was used or declared within a macro we 69 /// won't offer a fixup for safety reasons. 70 InsideMacro, 71 }; 72 73 /// Information describing a failed check 74 struct FailureInfo { 75 std::string KindName; // Tag or misc info to be used as derived classes need 76 std::string Fixup; // The name that will be proposed as a fix-it hint 77 }; 78 79 /// Holds an identifier name check failure, tracking the kind of the 80 /// identifier, its possible fixup and the starting locations of all the 81 /// identifier usages. 82 struct NamingCheckFailure { 83 FailureInfo Info; 84 85 /// Whether the failure should be fixed or not. 86 /// 87 /// e.g.: if the identifier was used or declared within a macro we won't 88 /// offer a fixup for safety reasons. shouldFixNamingCheckFailure89 bool shouldFix() const { 90 return FixStatus == ShouldFixStatus::ShouldFix && !Info.Fixup.empty(); 91 } 92 shouldNotifyNamingCheckFailure93 bool shouldNotify() const { 94 return FixStatus < ShouldFixStatus::IgnoreFailureThreshold; 95 } 96 97 ShouldFixStatus FixStatus = ShouldFixStatus::ShouldFix; 98 99 /// A set of all the identifier usages starting SourceLocation. 100 llvm::DenseSet<SourceLocation> RawUsageLocs; 101 102 NamingCheckFailure() = default; 103 }; 104 105 using NamingCheckId = std::pair<SourceLocation, StringRef>; 106 107 using NamingCheckFailureMap = 108 llvm::DenseMap<NamingCheckId, NamingCheckFailure>; 109 110 /// Check Macros for style violations. 111 void checkMacro(const SourceManager &SourceMgr, const Token &MacroNameTok, 112 const MacroInfo *MI); 113 114 /// Add a usage of a macro if it already has a violation. 115 void expandMacro(const Token &MacroNameTok, const MacroInfo *MI); 116 117 void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl, 118 SourceRange Range, const SourceManager *SourceMgr = nullptr); 119 120 /// Convenience method when the usage to be added is a NamedDecl. 121 void addUsage(const NamedDecl *Decl, SourceRange Range, 122 const SourceManager *SourceMgr = nullptr); 123 124 void checkNamedDecl(const NamedDecl *Decl, const SourceManager &SourceMgr); 125 126 protected: 127 /// Overridden by derived classes, returns information about if and how a Decl 128 /// failed the check. A 'std::nullopt' result means the Decl did not fail the 129 /// check. 130 virtual std::optional<FailureInfo> 131 getDeclFailureInfo(const NamedDecl *Decl, const SourceManager &SM) const = 0; 132 133 /// Overridden by derived classes, returns information about if and how a 134 /// macro failed the check. A 'std::nullopt' result means the macro did not 135 /// fail the check. 136 virtual std::optional<FailureInfo> 137 getMacroFailureInfo(const Token &MacroNameTok, 138 const SourceManager &SM) const = 0; 139 140 /// Represents customized diagnostic text and how arguments should be applied. 141 /// Example usage: 142 /// 143 /// return DiagInfo{"my %1 very %2 special %3 text", 144 /// [=](DiagnosticBuilder &diag) { 145 /// diag << arg1 << arg2 << arg3; 146 /// }}; 147 struct DiagInfo { 148 std::string Text; 149 llvm::unique_function<void(DiagnosticBuilder &)> ApplyArgs; 150 }; 151 152 /// Overridden by derived classes, returns a description of the diagnostic 153 /// that should be emitted for the given failure. The base class will then 154 /// further customize the diagnostic by adding info about whether the fix-it 155 /// can be automatically applied or not. 156 virtual DiagInfo getDiagInfo(const NamingCheckId &ID, 157 const NamingCheckFailure &Failure) const = 0; 158 159 private: 160 NamingCheckFailureMap NamingCheckFailures; 161 const bool AggressiveDependentMemberLookup; 162 }; 163 164 } // namespace tidy 165 } // namespace clang 166 167 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H 168