blob: fd5b32075cbe661e36a658b2b31cfe56c42d3e01 [file] [log] [blame]
Olivier Deprezf4ef2d02021-04-20 13:36:24 +02001//===--- 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
20namespace clang {
21
22class MacroInfo;
23
24namespace tidy {
25
26/// Base class for clang-tidy checks that want to flag declarations and/or
27/// macros for renaming based on customizable criteria.
28class RenamerClangTidyCheck : public ClangTidyCheck {
29public:
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.
90 bool ShouldFix() const {
91 return FixStatus == ShouldFixStatus::ShouldFix && !Info.Fixup.empty();
92 }
93
94 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
125protected:
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
157private:
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