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