• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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