aboutsummaryrefslogtreecommitdiff
path: root/clang-tidy
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2014-06-05 13:31:45 +0000
committerAlexander Kornienko <alexfh@google.com>2014-06-05 13:31:45 +0000
commitac560ec8cb8ae943afe2f10a954f70b146cd1cd6 (patch)
treea8c407786a6d9933e178a1fdfcd9e6080af49ec4 /clang-tidy
parente04d0b1c607170f31ce312ee2c6181bbda6f1ee1 (diff)
Allow per-file clang-tidy options.
Summary: This patch makes it possible for clang-tidy clients to provide different options for different translation units. The option, which doesn't make sense to be file-dependent, was moved to a separate ClangTidyGlobalOptions struct. Added parsing of ClangTidyOptions. Reviewers: klimek Reviewed By: klimek Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D3979 git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@210260 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-tidy')
-rw-r--r--clang-tidy/ClangTidy.cpp84
-rw-r--r--clang-tidy/ClangTidy.h23
-rw-r--r--clang-tidy/ClangTidyDiagnosticConsumer.cpp52
-rw-r--r--clang-tidy/ClangTidyDiagnosticConsumer.h71
-rw-r--r--clang-tidy/ClangTidyModule.cpp5
-rw-r--r--clang-tidy/ClangTidyModule.h2
-rw-r--r--clang-tidy/ClangTidyOptions.cpp18
-rw-r--r--clang-tidy/ClangTidyOptions.h71
-rw-r--r--clang-tidy/tool/ClangTidyMain.cpp21
9 files changed, 249 insertions, 98 deletions
diff --git a/clang-tidy/ClangTidy.cpp b/clang-tidy/ClangTidy.cpp
index 65c10f4c..5a3af2c2 100644
--- a/clang-tidy/ClangTidy.cpp
+++ b/clang-tidy/ClangTidy.cpp
@@ -169,51 +169,63 @@ private:
unsigned AppliedFixes;
};
+class ClangTidyASTConsumer : public MultiplexConsumer {
+public:
+ ClangTidyASTConsumer(const SmallVectorImpl<ASTConsumer *> &Consumers,
+ std::unique_ptr<ast_matchers::MatchFinder> Finder,
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks)
+ : MultiplexConsumer(Consumers), Finder(std::move(Finder)),
+ Checks(std::move(Checks)) {}
+
+private:
+ std::unique_ptr<ast_matchers::MatchFinder> Finder;
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+};
+
} // namespace
ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
- ClangTidyContext &Context, const ClangTidyOptions &Options)
- : Context(Context), CheckFactories(new ClangTidyCheckFactories),
- Options(Options) {
+ ClangTidyContext &Context)
+ : Context(Context), CheckFactories(new ClangTidyCheckFactories) {
for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(),
E = ClangTidyModuleRegistry::end();
I != E; ++I) {
std::unique_ptr<ClangTidyModule> Module(I->instantiate());
Module->addCheckFactories(*CheckFactories);
}
-
- CheckFactories->createChecks(Context.getChecksFilter(), Checks);
-
- for (ClangTidyCheck *Check : Checks) {
- Check->setContext(&Context);
- Check->registerMatchers(&Finder);
- }
}
-ClangTidyASTConsumerFactory::~ClangTidyASTConsumerFactory() {
- for (ClangTidyCheck *Check : Checks)
- delete Check;
-}
clang::ASTConsumer *ClangTidyASTConsumerFactory::CreateASTConsumer(
clang::CompilerInstance &Compiler, StringRef File) {
// FIXME: Move this to a separate method, so that CreateASTConsumer doesn't
// modify Compiler.
Context.setSourceManager(&Compiler.getSourceManager());
- for (ClangTidyCheck *Check : Checks)
+ Context.setCurrentFile(File);
+
+ std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
+ ChecksFilter &Filter = Context.getChecksFilter();
+ CheckFactories->createChecks(Filter, Checks);
+
+ std::unique_ptr<ast_matchers::MatchFinder> Finder(
+ new ast_matchers::MatchFinder);
+ for (auto &Check : Checks) {
+ Check->setContext(&Context);
+ Check->registerMatchers(&*Finder);
Check->registerPPCallbacks(Compiler);
+ }
SmallVector<ASTConsumer *, 2> Consumers;
- if (!CheckFactories->empty())
- Consumers.push_back(Finder.newASTConsumer());
+ if (!Checks.empty())
+ Consumers.push_back(Finder->newASTConsumer());
AnalyzerOptionsRef AnalyzerOptions = Compiler.getAnalyzerOpts();
// FIXME: Remove this option once clang's cfg-temporary-dtors option defaults
// to true.
AnalyzerOptions->Config["cfg-temporary-dtors"] =
- Options.AnalyzeTemporaryDtors ? "true" : "false";
+ Context.getOptions().AnalyzeTemporaryDtors ? "true" : "false";
- AnalyzerOptions->CheckersControlList = getCheckersControlList();
+ AnalyzerOptions->CheckersControlList = getCheckersControlList(Filter);
if (!AnalyzerOptions->CheckersControlList.empty()) {
AnalyzerOptions->AnalysisStoreOpt = RegionStoreModel;
AnalyzerOptions->AnalysisDiagOpt = PD_NONE;
@@ -226,17 +238,19 @@ clang::ASTConsumer *ClangTidyASTConsumerFactory::CreateASTConsumer(
new AnalyzerDiagnosticConsumer(Context));
Consumers.push_back(AnalysisConsumer);
}
- return new MultiplexConsumer(Consumers);
+ return new ClangTidyASTConsumer(Consumers, std::move(Finder),
+ std::move(Checks));
}
-std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
+std::vector<std::string>
+ClangTidyASTConsumerFactory::getCheckNames(ChecksFilter &Filter) {
std::vector<std::string> CheckNames;
for (const auto &CheckFactory : *CheckFactories) {
- if (Context.getChecksFilter().isCheckEnabled(CheckFactory.first))
+ if (Filter.isCheckEnabled(CheckFactory.first))
CheckNames.push_back(CheckFactory.first);
}
- for (const auto &AnalyzerCheck : getCheckersControlList())
+ for (const auto &AnalyzerCheck : getCheckersControlList(Filter))
CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first);
std::sort(CheckNames.begin(), CheckNames.end());
@@ -244,15 +258,15 @@ std::vector<std::string> ClangTidyASTConsumerFactory::getCheckNames() {
}
ClangTidyASTConsumerFactory::CheckersList
-ClangTidyASTConsumerFactory::getCheckersControlList() {
+ClangTidyASTConsumerFactory::getCheckersControlList(ChecksFilter &Filter) {
CheckersList List;
bool AnalyzerChecksEnabled = false;
for (StringRef CheckName : StaticAnalyzerChecks) {
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
- AnalyzerChecksEnabled |=
- Context.getChecksFilter().isCheckEnabled(Checker) &&
- !CheckName.startswith("debug");
+ AnalyzerChecksEnabled =
+ AnalyzerChecksEnabled ||
+ (!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker));
}
if (AnalyzerChecksEnabled) {
@@ -267,8 +281,7 @@ ClangTidyASTConsumerFactory::getCheckersControlList() {
std::string Checker((AnalyzerCheckNamePrefix + CheckName).str());
if (CheckName.startswith("core") ||
- (!CheckName.startswith("debug") &&
- Context.getChecksFilter().isCheckEnabled(Checker)))
+ (!CheckName.startswith("debug") && Filter.isCheckEnabled(Checker)))
List.push_back(std::make_pair(CheckName, true));
}
}
@@ -291,17 +304,18 @@ void ClangTidyCheck::setName(StringRef Name) {
}
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
- clang::tidy::ClangTidyContext Context(Options);
- ClangTidyASTConsumerFactory Factory(Context, Options);
- return Factory.getCheckNames();
+ clang::tidy::ClangTidyContext Context(
+ new DefaultOptionsProvider(ClangTidyGlobalOptions(), Options));
+ ClangTidyASTConsumerFactory Factory(Context);
+ return Factory.getCheckNames(Context.getChecksFilter());
}
-ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
+ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
std::vector<ClangTidyError> *Errors) {
ClangTool Tool(Compilations, InputFiles);
- clang::tidy::ClangTidyContext Context(Options);
+ clang::tidy::ClangTidyContext Context(OptionsProvider);
ClangTidyDiagnosticConsumer DiagConsumer(Context);
Tool.setDiagnosticConsumer(&DiagConsumer);
@@ -328,7 +342,7 @@ ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
ClangTidyASTConsumerFactory *ConsumerFactory;
};
- Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context, Options)));
+ Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context)));
*Errors = Context.getErrors();
return Context.getStats();
}
diff --git a/clang-tidy/ClangTidy.h b/clang-tidy/ClangTidy.h
index 51fb2fe9..8b181fc8 100644
--- a/clang-tidy/ClangTidy.h
+++ b/clang-tidy/ClangTidy.h
@@ -16,6 +16,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Tooling/Refactoring.h"
+#include <memory>
#include <vector>
namespace clang {
@@ -95,26 +96,21 @@ class ClangTidyCheckFactories;
class ClangTidyASTConsumerFactory {
public:
- ClangTidyASTConsumerFactory(ClangTidyContext &Context,
- const ClangTidyOptions &Options);
- ~ClangTidyASTConsumerFactory();
+ ClangTidyASTConsumerFactory(ClangTidyContext &Context);
/// \brief Returns an ASTConsumer that runs the specified clang-tidy checks.
clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler,
StringRef File);
/// \brief Get the list of enabled checks.
- std::vector<std::string> getCheckNames();
+ std::vector<std::string> getCheckNames(ChecksFilter &Filter);
private:
typedef std::vector<std::pair<std::string, bool> > CheckersList;
- CheckersList getCheckersControlList();
+ CheckersList getCheckersControlList(ChecksFilter &Filter);
- SmallVector<ClangTidyCheck *, 8> Checks;
ClangTidyContext &Context;
- ast_matchers::MatchFinder Finder;
std::unique_ptr<ClangTidyCheckFactories> CheckFactories;
- ClangTidyOptions Options;
};
/// \brief Fills the list of check names that are enabled when the provided
@@ -122,10 +118,13 @@ private:
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options);
/// \brief Run a set of clang-tidy checks on a set of files.
-ClangTidyStats runClangTidy(const ClangTidyOptions &Options,
- const tooling::CompilationDatabase &Compilations,
- ArrayRef<std::string> InputFiles,
- std::vector<ClangTidyError> *Errors);
+///
+/// Takes ownership of the \c OptionsProvider.
+ClangTidyStats
+runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
+ const tooling::CompilationDatabase &Compilations,
+ ArrayRef<std::string> InputFiles,
+ std::vector<ClangTidyError> *Errors);
// FIXME: This interface will need to be significantly extended to be useful.
// FIXME: Implement confidence levels for displaying/fixing errors.
diff --git a/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index 625f92ae..807e48b0 100644
--- a/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -154,8 +154,12 @@ bool ChecksFilter::isCheckEnabled(StringRef Name, bool Enabled) {
return Enabled;
}
-ClangTidyContext::ClangTidyContext(const ClangTidyOptions &Options)
- : DiagEngine(nullptr), Options(Options), Filter(Options.Checks) {}
+ClangTidyContext::ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider)
+ : DiagEngine(nullptr), OptionsProvider(OptionsProvider) {
+ // Before the first translation unit we can get errors related to command-line
+ // parsing, use empty string for the file name in this case.
+ setCurrentFile("");
+}
DiagnosticBuilder ClangTidyContext::diag(
StringRef CheckName, SourceLocation Loc, StringRef Description,
@@ -190,6 +194,24 @@ void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
DiagEngine->setSourceManager(SourceMgr);
}
+void ClangTidyContext::setCurrentFile(StringRef File) {
+ CurrentFile = File;
+ CheckFilter.reset(new ChecksFilter(getOptions().Checks));
+}
+
+const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const {
+ return OptionsProvider->getGlobalOptions();
+}
+
+const ClangTidyOptions &ClangTidyContext::getOptions() const {
+ return OptionsProvider->getOptions(CurrentFile);
+}
+
+ChecksFilter &ClangTidyContext::getChecksFilter() {
+ assert(CheckFilter != nullptr);
+ return *CheckFilter;
+}
+
/// \brief Store a \c ClangTidyError.
void ClangTidyContext::storeError(const ClangTidyError &Error) {
Errors.push_back(Error);
@@ -204,8 +226,8 @@ StringRef ClangTidyContext::getCheckName(unsigned DiagnosticID) const {
}
ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx)
- : Context(Ctx), HeaderFilter(Ctx.getOptions().HeaderFilterRegex),
- LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false) {
+ : Context(Ctx), LastErrorRelatesToUserCode(false),
+ LastErrorPassesLineFilter(false) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
Diags.reset(new DiagnosticsEngine(
IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
@@ -274,11 +296,18 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
checkFilters(Info.getLocation());
}
+void ClangTidyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP) {
+ // Before the first translation unit we don't need HeaderFilter, as we
+ // shouldn't get valid source locations in diagnostics.
+ HeaderFilter.reset(new llvm::Regex(Context.getOptions().HeaderFilterRegex));
+}
+
bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
unsigned LineNumber) const {
- if (Context.getOptions().LineFilter.empty())
+ if (Context.getGlobalOptions().LineFilter.empty())
return true;
- for (const FileFilter& Filter : Context.getOptions().LineFilter) {
+ for (const FileFilter& Filter : Context.getGlobalOptions().LineFilter) {
if (FileName.endswith(Filter.Name)) {
if (Filter.LineRanges.empty())
return true;
@@ -319,10 +348,15 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location) {
}
StringRef FileName(File->getName());
+ assert(LastErrorRelatesToUserCode || Sources.isInMainFile(Location) ||
+ HeaderFilter != nullptr);
+ LastErrorRelatesToUserCode = LastErrorRelatesToUserCode ||
+ Sources.isInMainFile(Location) ||
+ HeaderFilter->match(FileName);
+
unsigned LineNumber = Sources.getExpansionLineNumber(Location);
- LastErrorRelatesToUserCode |=
- Sources.isInMainFile(Location) || HeaderFilter.match(FileName);
- LastErrorPassesLineFilter |= passesLineFilter(FileName, LineNumber);
+ LastErrorPassesLineFilter =
+ LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber);
}
namespace {
diff --git a/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tidy/ClangTidyDiagnosticConsumer.h
index 926a3b43..4dac7b6c 100644
--- a/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -67,12 +67,13 @@ struct ClangTidyError {
/// \brief Filters checks by name.
class ChecksFilter {
public:
- // GlobList is a comma-separated list of globs (only '*' metacharacter is
- // supported) with optional '-' prefix to denote exclusion.
+ /// \brief \p GlobList is a comma-separated list of globs (only '*'
+ /// metacharacter is supported) with optional '-' prefix to denote exclusion.
ChecksFilter(StringRef GlobList);
- // Returns true if the check with the specified Name should be enabled.
- // The result is the last matching glob's Positive flag. If Name is not
- // matched by any globs, the check is not enabled.
+
+ /// \brief Returns \c true if the check with the specified \p Name should be
+ /// enabled. The result is the last matching glob's Positive flag. If \p Name
+ /// is not matched by any globs, the check is not enabled.
bool isCheckEnabled(StringRef Name) { return isCheckEnabled(Name, false); }
private:
@@ -83,6 +84,8 @@ private:
std::unique_ptr<ChecksFilter> NextFilter;
};
+/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy
+/// run.
struct ClangTidyStats {
ClangTidyStats()
: ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
@@ -111,7 +114,10 @@ struct ClangTidyStats {
/// \endcode
class ClangTidyContext {
public:
- ClangTidyContext(const ClangTidyOptions &Options);
+ /// \brief Initializes \c ClangTidyContext instance.
+ ///
+ /// Takes ownership of the \c OptionsProvider.
+ ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider);
/// \brief Report any errors detected using this method.
///
@@ -122,37 +128,55 @@ public:
StringRef Message,
DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
- /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
- /// correctly.
- ///
- /// This is called from the \c ClangTidyCheck base class.
- void setDiagnosticsEngine(DiagnosticsEngine *Engine);
-
/// \brief Sets the \c SourceManager of the used \c DiagnosticsEngine.
///
/// This is called from the \c ClangTidyCheck base class.
void setSourceManager(SourceManager *SourceMgr);
+ /// \brief Should be called when starting to process new translation unit.
+ void setCurrentFile(StringRef File);
+
/// \brief Returns the name of the clang-tidy check which produced this
/// diagnostic ID.
StringRef getCheckName(unsigned DiagnosticID) const;
- ChecksFilter &getChecksFilter() { return Filter; }
- const ClangTidyOptions &getOptions() const { return Options; }
+ /// \brief Returns check filter for the \c CurrentFile.
+ ChecksFilter &getChecksFilter();
+
+ /// \brief Returns global options.
+ const ClangTidyGlobalOptions &getGlobalOptions() const;
+
+ /// \brief Returns options for \c CurrentFile.
+ const ClangTidyOptions &getOptions() const;
+
+ /// \brief Returns \c ClangTidyStats containing issued and ignored diagnostic
+ /// counters.
const ClangTidyStats &getStats() const { return Stats; }
+
+ /// \brief Returns all collected errors.
const std::vector<ClangTidyError> &getErrors() const { return Errors; }
+
+ /// \brief Clears collected errors.
void clearErrors() { Errors.clear(); }
private:
- friend class ClangTidyDiagnosticConsumer; // Calls storeError().
+ // Calls setDiagnosticsEngine() and storeError().
+ friend class ClangTidyDiagnosticConsumer;
- /// \brief Store a \c ClangTidyError.
+ /// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
+ /// correctly.
+ void setDiagnosticsEngine(DiagnosticsEngine *Engine);
+
+ /// \brief Store an \p Error.
void storeError(const ClangTidyError &Error);
std::vector<ClangTidyError> Errors;
DiagnosticsEngine *DiagEngine;
- ClangTidyOptions Options;
- ChecksFilter Filter;
+ std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
+
+ std::string CurrentFile;
+ std::unique_ptr<ChecksFilter> CheckFilter;
+
ClangTidyStats Stats;
llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
@@ -173,18 +197,25 @@ public:
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) override;
- // Flushes the internal diagnostics buffer to the ClangTidyContext.
+ /// \brief Sets \c HeaderFilter to the value configured for this file.
+ void BeginSourceFile(const LangOptions &LangOpts,
+ const Preprocessor *PP) override;
+
+ /// \brief Flushes the internal diagnostics buffer to the ClangTidyContext.
void finish() override;
private:
void finalizeLastError();
+
+ /// \brief Updates \c LastErrorRelatesToUserCode and LastErrorPassesLineFilter
+ /// according to the diagnostic \p Location.
void checkFilters(SourceLocation Location);
bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
ClangTidyContext &Context;
- llvm::Regex HeaderFilter;
std::unique_ptr<DiagnosticsEngine> Diags;
SmallVector<ClangTidyError, 8> Errors;
+ std::unique_ptr<llvm::Regex> HeaderFilter;
bool LastErrorRelatesToUserCode;
bool LastErrorPassesLineFilter;
};
diff --git a/clang-tidy/ClangTidyModule.cpp b/clang-tidy/ClangTidyModule.cpp
index b79194d4..40812a2e 100644
--- a/clang-tidy/ClangTidyModule.cpp
+++ b/clang-tidy/ClangTidyModule.cpp
@@ -27,12 +27,13 @@ void ClangTidyCheckFactories::addCheckFactory(StringRef Name,
}
void ClangTidyCheckFactories::createChecks(
- ChecksFilter &Filter, SmallVectorImpl<ClangTidyCheck *> &Checks) {
+ ChecksFilter &Filter,
+ std::vector<std::unique_ptr<ClangTidyCheck>> &Checks) {
for (const auto &Factory : Factories) {
if (Filter.isCheckEnabled(Factory.first)) {
ClangTidyCheck *Check = Factory.second->createCheck();
Check->setName(Factory.first);
- Checks.push_back(Check);
+ Checks.emplace_back(Check);
}
}
}
diff --git a/clang-tidy/ClangTidyModule.h b/clang-tidy/ClangTidyModule.h
index 00a5a8d4..625be7aa 100644
--- a/clang-tidy/ClangTidyModule.h
+++ b/clang-tidy/ClangTidyModule.h
@@ -87,7 +87,7 @@ public:
///
/// The caller takes ownership of the return \c ClangTidyChecks.
void createChecks(ChecksFilter &Filter,
- SmallVectorImpl<ClangTidyCheck *> &Checks);
+ std::vector<std::unique_ptr<ClangTidyCheck>> &Checks);
typedef std::map<std::string, CheckFactoryBase *> FactoryMap;
FactoryMap::const_iterator begin() const { return Factories.begin(); }
diff --git a/clang-tidy/ClangTidyOptions.cpp b/clang-tidy/ClangTidyOptions.cpp
index fcf66ee8..93e12ca0 100644
--- a/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tidy/ClangTidyOptions.cpp
@@ -10,6 +10,7 @@
#include "ClangTidyOptions.h"
#include "llvm/Support/YAMLTraits.h"
+using clang::tidy::ClangTidyOptions;
using clang::tidy::FileFilter;
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
@@ -46,6 +47,14 @@ template <> struct MappingTraits<FileFilter> {
}
};
+template <> struct MappingTraits<ClangTidyOptions> {
+ static void mapping(IO &IO, ClangTidyOptions &Options) {
+ IO.mapOptional("Checks", Options.Checks);
+ IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
+ IO.mapOptional("AnalyzeTemporaryDtors", Options.AnalyzeTemporaryDtors);
+ }
+};
+
} // namespace yaml
} // namespace llvm
@@ -54,11 +63,18 @@ namespace tidy {
/// \brief Parses -line-filter option and stores it to the \c Options.
llvm::error_code parseLineFilter(const std::string &LineFilter,
- clang::tidy::ClangTidyOptions &Options) {
+ clang::tidy::ClangTidyGlobalOptions &Options) {
llvm::yaml::Input Input(LineFilter);
Input >> Options.LineFilter;
return Input.error();
}
+llvm::error_code parseConfiguration(const std::string &Config,
+ clang::tidy::ClangTidyOptions &Options) {
+ llvm::yaml::Input Input(Config);
+ Input >> Options;
+ return Input.error();
+}
+
} // namespace tidy
} // namespace clang
diff --git a/clang-tidy/ClangTidyOptions.h b/clang-tidy/ClangTidyOptions.h
index 60b38eab..1a5a92e9 100644
--- a/clang-tidy/ClangTidyOptions.h
+++ b/clang-tidy/ClangTidyOptions.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/system_error.h"
#include <string>
#include <utility>
@@ -18,32 +19,82 @@
namespace clang {
namespace tidy {
+/// \brief Contains a list of line ranges in a single file.
struct FileFilter {
+ /// \brief File name.
std::string Name;
- // LineRange is a pair<start, end> (inclusive).
+
+ /// \brief LineRange is a pair<start, end> (inclusive).
typedef std::pair<unsigned, unsigned> LineRange;
+
+ /// \brief A list of line ranges in this file, for which we show warnings.
std::vector<LineRange> LineRanges;
};
-/// \brief Contains options for clang-tidy.
+/// \brief Global options. These options are neither stored nor read from
+/// configuration files.
+struct ClangTidyGlobalOptions {
+ /// \brief Output warnings from certain line ranges of certain files only. If
+ /// this list is emtpy, it won't be applied.
+ std::vector<FileFilter> LineFilter;
+};
+
+/// \brief Contains options for clang-tidy. These options may be read from
+/// configuration files, and may be different for different translation units.
struct ClangTidyOptions {
+ /// \brief Allow all checks and no headers by default.
ClangTidyOptions() : Checks("*"), AnalyzeTemporaryDtors(false) {}
+
+ /// \brief Checks filter.
std::string Checks;
- // Output warnings from headers matching this filter. Warnings from main files
- // will always be displayed.
+ /// \brief Output warnings from headers matching this filter. Warnings from
+ /// main files will always be displayed.
std::string HeaderFilterRegex;
- // Output warnings from certain line ranges of certain files only. If this
- // list is emtpy, it won't be applied.
- std::vector<FileFilter> LineFilter;
-
+ /// \brief Turns on temporary destructor-based analysis.
bool AnalyzeTemporaryDtors;
};
-/// \brief Parses LineFilter from JSON and stores it to the \c Options.
+/// \brief Abstract interface for retrieving various ClangTidy options.
+class ClangTidyOptionsProvider {
+public:
+ virtual ~ClangTidyOptionsProvider() {}
+
+ /// \brief Returns global options, which are independent of the file.
+ virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0;
+
+ /// \brief Returns options applying to a specific translation unit with the
+ /// specified \p FileName.
+ virtual const ClangTidyOptions &getOptions(llvm::StringRef FileName) = 0;
+};
+
+/// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
+/// returns the same options for all files.
+class DefaultOptionsProvider : public ClangTidyOptionsProvider {
+public:
+ DefaultOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &Options)
+ : GlobalOptions(GlobalOptions), DefaultOptions(Options) {}
+ const ClangTidyGlobalOptions &getGlobalOptions() override {
+ return GlobalOptions;
+ }
+ const ClangTidyOptions &getOptions(llvm::StringRef) override {
+ return DefaultOptions;
+ }
+
+private:
+ ClangTidyGlobalOptions GlobalOptions;
+ ClangTidyOptions DefaultOptions;
+};
+
+/// \brief Parses LineFilter from JSON and stores it to the \p Options.
llvm::error_code parseLineFilter(const std::string &LineFilter,
- clang::tidy::ClangTidyOptions &Options);
+ clang::tidy::ClangTidyGlobalOptions &Options);
+
+/// \brief Parses configuration from JSON and stores it to the \p Options.
+llvm::error_code parseConfiguration(const std::string &Config,
+ clang::tidy::ClangTidyOptions &Options);
} // end namespace tidy
} // end namespace clang
diff --git a/clang-tidy/tool/ClangTidyMain.cpp b/clang-tidy/tool/ClangTidyMain.cpp
index f338805f..3447a971 100644
--- a/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tidy/tool/ClangTidyMain.cpp
@@ -108,17 +108,19 @@ static void printStats(const clang::tidy::ClangTidyStats &Stats) {
int main(int argc, const char **argv) {
CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory);
- clang::tidy::ClangTidyOptions Options;
- Options.Checks = DefaultChecks + Checks;
- Options.HeaderFilterRegex = HeaderFilter;
- Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+ clang::tidy::ClangTidyGlobalOptions GlobalOptions;
if (llvm::error_code Err =
- clang::tidy::parseLineFilter(LineFilter, Options)) {
+ clang::tidy::parseLineFilter(LineFilter, GlobalOptions)) {
llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
return 1;
}
+ clang::tidy::ClangTidyOptions Options;
+ Options.Checks = DefaultChecks + Checks;
+ Options.HeaderFilterRegex = HeaderFilter;
+ Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+
std::vector<std::string> EnabledChecks = clang::tidy::getCheckNames(Options);
// FIXME: Allow using --list-checks without positional arguments.
@@ -136,10 +138,13 @@ int main(int argc, const char **argv) {
return 1;
}
+ // TODO: Implement configuration file reading and a "real" options provider.
+ auto OptionsProvider =
+ new clang::tidy::DefaultOptionsProvider(GlobalOptions, Options);
std::vector<clang::tidy::ClangTidyError> Errors;
- clang::tidy::ClangTidyStats Stats =
- clang::tidy::runClangTidy(Options, OptionsParser.getCompilations(),
- OptionsParser.getSourcePathList(), &Errors);
+ clang::tidy::ClangTidyStats Stats = clang::tidy::runClangTidy(
+ OptionsProvider, OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList(), &Errors);
clang::tidy::handleErrors(Errors, Fix);
printStats(Stats);