blob: def04c917bbc948b47d3aa4fccaadc2ea46eba59 [file] [log] [blame]
//===--- RenamerClangTidyCheck.h - clang-tidy -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H
#include "../ClangTidyCheck.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/Optional.h"
#include <string>
#include <utility>
namespace clang {
class MacroInfo;
namespace tidy {
/// Base class for clang-tidy checks that want to flag declarations and/or
/// macros for renaming based on customizable criteria.
class RenamerClangTidyCheck : public ClangTidyCheck {
public:
RenamerClangTidyCheck(StringRef CheckName, ClangTidyContext *Context);
~RenamerClangTidyCheck();
/// Derived classes should not implement any matching logic themselves; this
/// class will do the matching and call the derived class'
/// getDeclFailureInfo() and getMacroFailureInfo() for determining whether a
/// given identifier passes or fails the check.
void registerMatchers(ast_matchers::MatchFinder *Finder) override final;
void
check(const ast_matchers::MatchFinder::MatchResult &Result) override final;
void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
Preprocessor *ModuleExpanderPP) override final;
void onEndOfTranslationUnit() override final;
/// Derived classes that override this function should call this method from
/// the overridden method.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
/// This enum will be used in %select of the diagnostic message.
/// Each value below IgnoreFailureThreshold should have an error message.
enum class ShouldFixStatus {
ShouldFix,
/// The fixup will conflict with a language keyword,
/// so we can't fix it automatically.
ConflictsWithKeyword,
/// The fixup will conflict with a macro
/// definition, so we can't fix it
/// automatically.
ConflictsWithMacroDefinition,
/// The fixup results in an identifier that is not a valid c/c++ identifier.
FixInvalidIdentifier,
/// Values pass this threshold will be ignored completely
/// i.e no message, no fixup.
IgnoreFailureThreshold,
/// If the identifier was used or declared within a macro we
/// won't offer a fixup for safety reasons.
InsideMacro,
};
/// Information describing a failed check
struct FailureInfo {
std::string KindName; // Tag or misc info to be used as derived classes need
std::string Fixup; // The name that will be proposed as a fix-it hint
};
/// Holds an identifier name check failure, tracking the kind of the
/// identifier, its possible fixup and the starting locations of all the
/// identifier usages.
struct NamingCheckFailure {
FailureInfo Info;
/// Whether the failure should be fixed or not.
///
/// e.g.: if the identifier was used or declared within a macro we won't
/// offer a fixup for safety reasons.
bool shouldFix() const {
return FixStatus == ShouldFixStatus::ShouldFix && !Info.Fixup.empty();
}
bool shouldNotify() const {
return FixStatus < ShouldFixStatus::IgnoreFailureThreshold;
}
ShouldFixStatus FixStatus = ShouldFixStatus::ShouldFix;
/// A set of all the identifier usages starting SourceLocation.
llvm::DenseSet<SourceLocation> RawUsageLocs;
NamingCheckFailure() = default;
};
using NamingCheckId = std::pair<SourceLocation, std::string>;
using NamingCheckFailureMap =
llvm::DenseMap<NamingCheckId, NamingCheckFailure>;
/// Check Macros for style violations.
void checkMacro(SourceManager &SourceMgr, const Token &MacroNameTok,
const MacroInfo *MI);
/// Add a usage of a macro if it already has a violation.
void expandMacro(const Token &MacroNameTok, const MacroInfo *MI);
void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl,
SourceRange Range, SourceManager *SourceMgr = nullptr);
/// Convenience method when the usage to be added is a NamedDecl.
void addUsage(const NamedDecl *Decl, SourceRange Range,
SourceManager *SourceMgr = nullptr);
protected:
/// Overridden by derived classes, returns information about if and how a Decl
/// failed the check. A 'None' result means the Decl did not fail the check.
virtual llvm::Optional<FailureInfo>
getDeclFailureInfo(const NamedDecl *Decl, const SourceManager &SM) const = 0;
/// Overridden by derived classes, returns information about if and how a
/// macro failed the check. A 'None' result means the macro did not fail the
/// check.
virtual llvm::Optional<FailureInfo>
getMacroFailureInfo(const Token &MacroNameTok,
const SourceManager &SM) const = 0;
/// Represents customized diagnostic text and how arguments should be applied.
/// Example usage:
///
/// return DiagInfo{"my %1 very %2 special %3 text",
/// [=](DiagnosticBuilder &diag) {
/// diag << arg1 << arg2 << arg3;
/// }};
struct DiagInfo {
std::string Text;
llvm::unique_function<void(DiagnosticBuilder &)> ApplyArgs;
};
/// Overridden by derived classes, returns a description of the diagnostic
/// that should be emitted for the given failure. The base class will then
/// further customize the diagnostic by adding info about whether the fix-it
/// can be automatically applied or not.
virtual DiagInfo getDiagInfo(const NamingCheckId &ID,
const NamingCheckFailure &Failure) const = 0;
private:
NamingCheckFailureMap NamingCheckFailures;
const bool AggressiveDependentMemberLookup;
};
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_RENAMERCLANGTIDYCHECK_H