171 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_UTILS_RENAMERCLANGTIDYCHECK_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_RENAMERCLANGTIDYCHECK_H11 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 20namespace clang {21 22class MacroInfo;23 24namespace tidy {25 26/// Base class for clang-tidy checks that want to flag declarations and/or27/// macros for renaming based on customizable criteria.28class RenamerClangTidyCheck : public ClangTidyCheck {29public:30 RenamerClangTidyCheck(StringRef CheckName, ClangTidyContext *Context);31 ~RenamerClangTidyCheck() override;32 33 /// Derived classes should not implement any matching logic themselves; this34 /// class will do the matching and call the derived class'35 /// getDeclFailureInfo() and getMacroFailureInfo() for determining whether a36 /// 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 from44 /// 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 macro57 /// definition, so we can't fix it58 /// 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 completely65 /// i.e no message, no fixup.66 IgnoreFailureThreshold,67 68 /// If the identifier was used or declared within a macro we69 /// won't offer a fixup for safety reasons.70 InsideMacro,71 };72 73 /// Information describing a failed check74 struct FailureInfo {75 std::string KindName; // Tag or misc info to be used as derived classes need76 std::string Fixup; // The name that will be proposed as a fix-it hint77 };78 79 /// Holds an identifier name check failure, tracking the kind of the80 /// identifier, its possible fixup and the starting locations of all the81 /// 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't88 /// offer a fixup for safety reasons.89 bool shouldFix() const {90 return FixStatus == ShouldFixStatus::ShouldFix && !Info.Fixup.empty();91 }92 93 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 Token &MacroNameTok, const MacroInfo *MI,112 const SourceManager &SourceMgr);113 114 /// Add a usage of a macro if it already has a violation.115 void expandMacro(const Token &MacroNameTok, const MacroInfo *MI,116 const SourceManager &SourceMgr);117 118 void addUsage(const NamedDecl *Decl, SourceRange Range,119 const SourceManager &SourceMgr);120 121protected:122 /// Overridden by derived classes, returns information about if and how a Decl123 /// failed the check. A 'std::nullopt' result means the Decl did not fail the124 /// check.125 virtual std::optional<FailureInfo>126 getDeclFailureInfo(const NamedDecl *Decl, const SourceManager &SM) const = 0;127 128 /// Overridden by derived classes, returns information about if and how a129 /// macro failed the check. A 'std::nullopt' result means the macro did not130 /// fail the check.131 virtual std::optional<FailureInfo>132 getMacroFailureInfo(const Token &MacroNameTok,133 const SourceManager &SM) const = 0;134 135 /// Represents customized diagnostic text and how arguments should be applied.136 /// Example usage:137 ///138 /// return DiagInfo{"my %1 very %2 special %3 text",139 /// [=](DiagnosticBuilder &diag) {140 /// diag << arg1 << arg2 << arg3;141 /// }};142 struct DiagInfo {143 std::string Text;144 llvm::unique_function<void(DiagnosticBuilder &)> ApplyArgs;145 };146 147 /// Overridden by derived classes, returns a description of the diagnostic148 /// that should be emitted for the given failure. The base class will then149 /// further customize the diagnostic by adding info about whether the fix-it150 /// can be automatically applied or not.151 virtual DiagInfo getDiagInfo(const NamingCheckId &ID,152 const NamingCheckFailure &Failure) const = 0;153 154private:155 // Manage additions to the Failure/usage map156 //157 // return the result of NamingCheckFailures::try_emplace() if the usage was158 // accepted.159 std::pair<NamingCheckFailureMap::iterator, bool>160 addUsage(const RenamerClangTidyCheck::NamingCheckId &FailureId,161 SourceRange UsageRange, const SourceManager &SourceMgr);162 163 NamingCheckFailureMap NamingCheckFailures;164 const bool AggressiveDependentMemberLookup;165};166 167} // namespace tidy168} // namespace clang169 170#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_RENAMERCLANGTIDYCHECK_H171