blob: 2985732039521d926d6be7b390e566f82cc416f9 [file] [log] [blame]
//===--- ClangTidy.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_CLANGTIDY_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDY_H
#include "ClangTidyDiagnosticConsumer.h"
#include "ClangTidyOptions.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <type_traits>
#include <vector>
namespace clang {
class CompilerInstance;
namespace tooling {
class CompilationDatabase;
}
namespace tidy {
/// \brief Provides access to the ``ClangTidyCheck`` options via check-local
/// names.
///
/// Methods of this class prepend ``CheckName + "."`` to translate check-local
/// option names to global option names.
class OptionsView {
public:
/// \brief Initializes the instance using \p CheckName + "." as a prefix.
OptionsView(StringRef CheckName,
const ClangTidyOptions::OptionMap &CheckOptions);
/// \brief Read a named option from the ``Context``.
///
/// Reads the option with the check-local name \p LocalName from the
/// ``CheckOptions``. If the corresponding key is not present, returns
/// \p Default.
std::string get(StringRef LocalName, StringRef Default) const;
/// \brief Read a named option from the ``Context``.
///
/// Reads the option with the check-local name \p LocalName from local or
/// global ``CheckOptions``. Gets local option first. If local is not present,
/// falls back to get global option. If global option is not present either,
/// returns Default.
std::string getLocalOrGlobal(StringRef LocalName, StringRef Default) const;
/// \brief Read a named option from the ``Context`` and parse it as an
/// integral type ``T``.
///
/// Reads the option with the check-local name \p LocalName from the
/// ``CheckOptions``. If the corresponding key is not present, returns
/// \p Default.
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
get(StringRef LocalName, T Default) const {
std::string Value = get(LocalName, "");
T Result = Default;
if (!Value.empty())
StringRef(Value).getAsInteger(10, Result);
return Result;
}
/// \brief Read a named option from the ``Context`` and parse it as an
/// integral type ``T``.
///
/// Reads the option with the check-local name \p LocalName from local or
/// global ``CheckOptions``. Gets local option first. If local is not present,
/// falls back to get global option. If global option is not present either,
/// returns Default.
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
getLocalOrGlobal(StringRef LocalName, T Default) const {
std::string Value = getLocalOrGlobal(LocalName, "");
T Result = Default;
if (!Value.empty())
StringRef(Value).getAsInteger(10, Result);
return Result;
}
/// \brief Stores an option with the check-local name \p LocalName with string
/// value \p Value to \p Options.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
StringRef Value) const;
/// \brief Stores an option with the check-local name \p LocalName with
/// ``int64_t`` value \p Value to \p Options.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
int64_t Value) const;
private:
std::string NamePrefix;
const ClangTidyOptions::OptionMap &CheckOptions;
};
/// \brief Base class for all clang-tidy checks.
///
/// To implement a ``ClangTidyCheck``, write a subclass and override some of the
/// base class's methods. E.g. to implement a check that validates namespace
/// declarations, override ``registerMatchers``:
///
/// ~~~{.cpp}
/// void registerMatchers(ast_matchers::MatchFinder *Finder) override {
/// Finder->addMatcher(namespaceDecl().bind("namespace"), this);
/// }
/// ~~~
///
/// and then override ``check(const MatchResult &Result)`` to do the actual
/// check for each match.
///
/// A new ``ClangTidyCheck`` instance is created per translation unit.
///
/// FIXME: Figure out whether carrying information from one TU to another is
/// useful/necessary.
class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
public:
/// \brief Initializes the check with \p CheckName and \p Context.
///
/// Derived classes must implement the constructor with this signature or
/// delegate it. If a check needs to read options, it can do this in the
/// constructor using the Options.get() methods below.
ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
: CheckName(CheckName), Context(Context),
Options(CheckName, Context->getOptions().CheckOptions) {
assert(Context != nullptr);
assert(!CheckName.empty());
}
/// \brief Override this to register ``PPCallbacks`` with ``Compiler``.
///
/// This should be used for clang-tidy checks that analyze preprocessor-
/// dependent properties, e.g. the order of include directives.
virtual void registerPPCallbacks(CompilerInstance &Compiler) {}
/// \brief Override this to register AST matchers with \p Finder.
///
/// This should be used by clang-tidy checks that analyze code properties that
/// dependent on AST knowledge.
///
/// You can register as many matchers as necessary with \p Finder. Usually,
/// "this" will be used as callback, but you can also specify other callback
/// classes. Thereby, different matchers can trigger different callbacks.
///
/// If you need to merge information between the different matchers, you can
/// store these as members of the derived class. However, note that all
/// matches occur in the order of the AST traversal.
virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
/// \brief ``ClangTidyChecks`` that register ASTMatchers should do the actual
/// work in here.
virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {}
/// \brief Add a diagnostic with the check's name.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description,
DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
/// \brief Should store all options supported by this check with their
/// current values or default values for options that haven't been overridden.
///
/// The check should use ``Options.store()`` to store each option it supports
/// whether it has the default value or it has been overridden.
virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {}
private:
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
StringRef getID() const override { return CheckName; }
std::string CheckName;
ClangTidyContext *Context;
protected:
OptionsView Options;
/// \brief Returns the main file name of the current translation unit.
StringRef getCurrentMainFile() const { return Context->getCurrentFile(); }
/// \brief Returns the language options from the context.
LangOptions getLangOpts() const { return Context->getLangOpts(); }
};
class ClangTidyCheckFactories;
class ClangTidyASTConsumerFactory {
public:
ClangTidyASTConsumerFactory(ClangTidyContext &Context);
/// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &Compiler, StringRef File);
/// \brief Get the list of enabled checks.
std::vector<std::string> getCheckNames();
/// \brief Get the union of options from all checks.
ClangTidyOptions::OptionMap getCheckOptions();
private:
ClangTidyContext &Context;
std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
};
/// \brief Fills the list of check names that are enabled when the provided
/// filters are applied.
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options,
bool AllowEnablingAnalyzerAlphaCheckers);
/// \brief Returns the effective check-specific options.
///
/// The method configures ClangTidy with the specified \p Options and collects
/// effective options from all created checks. The returned set of options
/// includes default check-specific options for all keys not overridden by \p
/// Options.
ClangTidyOptions::OptionMap
getCheckOptions(const ClangTidyOptions &Options,
bool AllowEnablingAnalyzerAlphaCheckers);
/// \brief Run a set of clang-tidy checks on a set of files.
///
/// \param EnableCheckProfile If provided, it enables check profile collection
/// in MatchFinder, and will contain the result of the profile.
/// \param StoreCheckProfile If provided, and EnableCheckProfile is true,
/// the profile will not be output to stderr, but will instead be stored
/// as a JSON file in the specified directory.
std::vector<ClangTidyError>
runClangTidy(clang::tidy::ClangTidyContext &Context,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
bool EnableCheckProfile = false,
llvm::StringRef StoreCheckProfile = StringRef());
// FIXME: This interface will need to be significantly extended to be useful.
// FIXME: Implement confidence levels for displaying/fixing errors.
//
/// \brief Displays the found \p Errors to the users. If \p Fix is true, \p
/// Errors containing fixes are automatically applied and reformatted. If no
/// clang-format configuration file is found, the given \P FormatStyle is used.
void handleErrors(llvm::ArrayRef<ClangTidyError> Errors,
ClangTidyContext &Context, bool Fix,
unsigned &WarningsAsErrorsCount,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
/// \brief Serializes replacements into YAML and writes them to the specified
/// output stream.
void exportReplacements(StringRef MainFilePath,
const std::vector<ClangTidyError> &Errors,
raw_ostream &OS);
} // end namespace tidy
} // end namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDY_H