Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -16,6 +16,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Tooling/Refactoring.h" +#include #include namespace clang { @@ -95,26 +96,21 @@ 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 getCheckNames(); + std::vector getCheckNames(ChecksFilter &Filter); private: typedef std::vector > CheckersList; - CheckersList getCheckersControlList(); + CheckersList getCheckersControlList(ChecksFilter &Filter); - SmallVector Checks; ClangTidyContext &Context; - ast_matchers::MatchFinder Finder; std::unique_ptr CheckFactories; - ClangTidyOptions Options; }; /// \brief Fills the list of check names that are enabled when the provided @@ -122,10 +118,13 @@ std::vector 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 InputFiles, - std::vector *Errors); +/// +/// Takes ownership of the \c OptionsProvider. +ClangTidyStats +runClangTidy(ClangTidyOptionsProvider *OptionsProvider, + const tooling::CompilationDatabase &Compilations, + ArrayRef InputFiles, + std::vector *Errors); // FIXME: This interface will need to be significantly extended to be useful. // FIXME: Implement confidence levels for displaying/fixing errors. Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -169,51 +169,65 @@ unsigned AppliedFixes; }; +class ClangTidyASTConsumer : public MultiplexConsumer { +public: + ClangTidyASTConsumer(const SmallVectorImpl &Consumers, + std::unique_ptr Finder, + const SmallVectorImpl &Checks) + : MultiplexConsumer(Consumers), Finder(std::move(Finder)) { + for (ClangTidyCheck *Check : Checks) + this->Checks.emplace_back(Check); + } + +private: + std::unique_ptr Finder; + std::vector> 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 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); + + SmallVector Checks; + ChecksFilter &Filter = Context.getChecksFilter(); + CheckFactories->createChecks(Filter, Checks); + + std::unique_ptr Finder( + new ast_matchers::MatchFinder); + for (ClangTidyCheck *Check : Checks) { + Check->setContext(&Context); + Check->registerMatchers(&*Finder); Check->registerPPCallbacks(Compiler); + } SmallVector 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 +240,18 @@ new AnalyzerDiagnosticConsumer(Context)); Consumers.push_back(AnalysisConsumer); } - return new MultiplexConsumer(Consumers); + return new ClangTidyASTConsumer(Consumers, std::move(Finder), Checks); } -std::vector ClangTidyASTConsumerFactory::getCheckNames() { +std::vector +ClangTidyASTConsumerFactory::getCheckNames(ChecksFilter &Filter) { std::vector 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 +259,15 @@ } 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 +282,7 @@ 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 +305,18 @@ } std::vector 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 InputFiles, std::vector *Errors) { ClangTool Tool(Compilations, InputFiles); - clang::tidy::ClangTidyContext Context(Options); + clang::tidy::ClangTidyContext Context(OptionsProvider); ClangTidyDiagnosticConsumer DiagConsumer(Context); Tool.setDiagnosticConsumer(&DiagConsumer); @@ -328,7 +343,7 @@ ClangTidyASTConsumerFactory *ConsumerFactory; }; - Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context, Options))); + Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context))); *Errors = Context.getErrors(); return Context.getStats(); } Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tidy/ClangTidyDiagnosticConsumer.h @@ -60,12 +60,13 @@ /// \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: @@ -76,6 +77,8 @@ std::unique_ptr NextFilter; }; +/// \brief Contains displayed and ignored diagnostic counters for a ClangTidy +/// run. struct ClangTidyStats { ClangTidyStats() : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0), @@ -104,7 +107,10 @@ /// \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. /// @@ -115,37 +121,55 @@ 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 &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 Errors; DiagnosticsEngine *DiagEngine; - ClangTidyOptions Options; - ChecksFilter Filter; + std::unique_ptr OptionsProvider; + + StringRef CurrentFile; + std::unique_ptr CheckFilter; + ClangTidyStats Stats; llvm::DenseMap CheckNamesByDiagnosticID; @@ -166,18 +190,25 @@ 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 Diags; SmallVector Errors; + std::unique_ptr HeaderFilter; bool LastErrorRelatesToUserCode; bool LastErrorPassesLineFilter; }; Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -152,8 +152,12 @@ 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, @@ -188,6 +192,24 @@ 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); @@ -202,8 +224,8 @@ } ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx) - : Context(Ctx), HeaderFilter(Ctx.getOptions().HeaderFilterRegex), - LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false) { + : Context(Ctx), LastErrorRelatesToUserCode(false), + LastErrorPassesLineFilter(false) { IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); Diags.reset(new DiagnosticsEngine( IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, this, @@ -264,11 +286,18 @@ 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; @@ -309,10 +338,15 @@ } 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 { Index: clang-tidy/ClangTidyOptions.h =================================================================== --- clang-tidy/ClangTidyOptions.h +++ 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 #include @@ -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 (inclusive). + + /// \brief LineRange is a pair (inclusive). typedef std::pair LineRange; + + /// \brief A list of line ranges in this file, from where the warnings may be + /// displayed. std::vector LineRanges; }; -/// \brief Contains options for clang-tidy. +/// \brief Global options. These options are nor stored neither 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 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 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 { + ClangTidyGlobalOptions GlobalOptions; + ClangTidyOptions DefaultOptions; + +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; + } +}; + +/// \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 Index: clang-tidy/ClangTidyOptions.cpp =================================================================== --- clang-tidy/ClangTidyOptions.cpp +++ 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 { + 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 @@ /// \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 Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -108,17 +108,19 @@ 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; + // FIXME: Allow using --list-checks without positional arguments. if (ListChecks) { llvm::outs() << "Enabled checks:"; @@ -128,10 +130,13 @@ return 0; } + // TODO: Implement configuration file reading and a "real" options provider. + auto OptionsProvider = + new clang::tidy::DefaultOptionsProvider(GlobalOptions, Options); std::vector 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); Index: unittests/clang-tidy/ClangTidyOptionsTest.cpp =================================================================== --- unittests/clang-tidy/ClangTidyOptionsTest.cpp +++ unittests/clang-tidy/ClangTidyOptionsTest.cpp @@ -6,7 +6,7 @@ namespace test { TEST(ParseLineFilter, EmptyFilter) { - ClangTidyOptions Options; + ClangTidyGlobalOptions Options; EXPECT_FALSE(parseLineFilter("", Options)); EXPECT_TRUE(Options.LineFilter.empty()); EXPECT_FALSE(parseLineFilter("[]", Options)); @@ -14,7 +14,7 @@ } TEST(ParseLineFilter, InvalidFilter) { - ClangTidyOptions Options; + ClangTidyGlobalOptions Options; // TODO: Figure out why parsing succeeds here. EXPECT_FALSE(parseLineFilter("asdf", Options)); EXPECT_TRUE(Options.LineFilter.empty()); @@ -30,7 +30,7 @@ } TEST(ParseLineFilter, ValidFilter) { - ClangTidyOptions Options; + ClangTidyGlobalOptions Options; llvm::error_code Error = parseLineFilter( "[{\"name\":\"file1.cpp\",\"lines\":[[3,15],[20,30],[42,42]]}," "{\"name\":\"file2.h\"}," @@ -54,6 +54,18 @@ EXPECT_EQ(1000u, Options.LineFilter[2].LineRanges[0].second); } +TEST(ParseConfiguration, ValidConfiguration) { + ClangTidyOptions Options; + llvm::error_code Error = parseConfiguration("Checks: \"-*,misc-*\"\n" + "HeaderFilterRegex: \".*\"\n" + "AnalyzeTemporaryDtors: true\n", + Options); + EXPECT_FALSE(Error); + EXPECT_EQ("-*,misc-*", Options.Checks); + EXPECT_EQ(".*", Options.HeaderFilterRegex); + EXPECT_TRUE(Options.AnalyzeTemporaryDtors); +} + } // namespace test } // namespace tidy } // namespace clang Index: unittests/clang-tidy/ClangTidyTest.h =================================================================== --- unittests/clang-tidy/ClangTidyTest.h +++ unittests/clang-tidy/ClangTidyTest.h @@ -43,8 +43,8 @@ std::string runCheckOnCode(StringRef Code, std::vector *Errors = nullptr) { T Check; - ClangTidyOptions Options; - ClangTidyContext Context(Options); + ClangTidyContext Context( + new DefaultOptionsProvider(ClangTidyGlobalOptions(), ClangTidyOptions())); ClangTidyDiagnosticConsumer DiagConsumer(Context); Check.setContext(&Context); std::vector ArgCXX11(1, "-std=c++11");