summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Kornienko <alexfh@google.com>2014-09-04 14:23:36 +0000
committerAlexander Kornienko <alexfh@google.com>2014-09-04 14:23:36 +0000
commitd53d2686b31f83143a28d53135daaef595f396de (patch)
tree0c37c13cec880e2ea57f1b4fee749c2f5ce58325
parentc0ae1a038f67fdbd79843d26c42b943b1111cd08 (diff)
downloadbcm5719-llvm-d53d2686b31f83143a28d53135daaef595f396de.tar.gz
bcm5719-llvm-d53d2686b31f83143a28d53135daaef595f396de.zip
Implemented clang-tidy configurability via .clang-tidy files.
Summary: This adds a support for the .clang-tidy file reading using FileOptionsProvider, -dump-config option, and changes tests to not depend on default checks set. Reviewers: klimek, bkramer, djasper Reviewed By: djasper Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D5186 llvm-svn: 217155
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidy.cpp14
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidy.h4
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp14
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h5
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyOptions.cpp127
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyOptions.h68
-rw-r--r--clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp66
-rw-r--r--clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy2
-rw-r--r--clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy2
-rw-r--r--clang-tools-extra/test/clang-tidy/config-files.cpp12
-rw-r--r--clang-tools-extra/test/clang-tidy/diagnostic.cpp2
-rw-r--r--clang-tools-extra/test/clang-tidy/validate-check-names.cpp2
-rw-r--r--clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp6
-rw-r--r--clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h6
14 files changed, 280 insertions, 50 deletions
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index ccf56f6fa3a..f543e2f1a99 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -314,17 +314,19 @@ void ClangTidyCheck::setName(StringRef Name) {
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options) {
clang::tidy::ClangTidyContext Context(
- new DefaultOptionsProvider(ClangTidyGlobalOptions(), Options));
+ llvm::make_unique<DefaultOptionsProvider>(ClangTidyGlobalOptions(),
+ Options));
ClangTidyASTConsumerFactory Factory(Context);
return Factory.getCheckNames(Context.getChecksFilter());
}
-ClangTidyStats runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
- const tooling::CompilationDatabase &Compilations,
- ArrayRef<std::string> InputFiles,
- std::vector<ClangTidyError> *Errors) {
+ClangTidyStats
+runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
+ const tooling::CompilationDatabase &Compilations,
+ ArrayRef<std::string> InputFiles,
+ std::vector<ClangTidyError> *Errors) {
ClangTool Tool(Compilations, InputFiles);
- clang::tidy::ClangTidyContext Context(OptionsProvider);
+ clang::tidy::ClangTidyContext Context(std::move(OptionsProvider));
ClangTidyDiagnosticConsumer DiagConsumer(Context);
Tool.setDiagnosticConsumer(&DiagConsumer);
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h
index 1112bf1b3e5..268a2d20471 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.h
+++ b/clang-tools-extra/clang-tidy/ClangTidy.h
@@ -118,10 +118,8 @@ private:
std::vector<std::string> getCheckNames(const ClangTidyOptions &Options);
/// \brief Run a set of clang-tidy checks on a set of files.
-///
-/// Takes ownership of the \c OptionsProvider.
ClangTidyStats
-runClangTidy(ClangTidyOptionsProvider *OptionsProvider,
+runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
std::vector<ClangTidyError> *Errors);
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
index 9d0b70045fe..49e20354e75 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -160,8 +160,9 @@ bool GlobList::contains(StringRef S, bool Contains) {
return Contains;
}
-ClangTidyContext::ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider)
- : DiagEngine(nullptr), OptionsProvider(OptionsProvider) {
+ClangTidyContext::ClangTidyContext(
+ std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider)
+ : DiagEngine(nullptr), OptionsProvider(std::move(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("");
@@ -202,7 +203,10 @@ void ClangTidyContext::setSourceManager(SourceManager *SourceMgr) {
void ClangTidyContext::setCurrentFile(StringRef File) {
CurrentFile = File;
- CheckFilter.reset(new GlobList(getOptions().Checks));
+ // Safeguard against options with unset values.
+ CurrentOptions = ClangTidyOptions::getDefaults().mergeWith(
+ OptionsProvider->getOptions(CurrentFile));
+ CheckFilter.reset(new GlobList(*getOptions().Checks));
}
void ClangTidyContext::setASTContext(ASTContext *Context) {
@@ -214,7 +218,7 @@ const ClangTidyGlobalOptions &ClangTidyContext::getGlobalOptions() const {
}
const ClangTidyOptions &ClangTidyContext::getOptions() const {
- return OptionsProvider->getOptions(CurrentFile);
+ return CurrentOptions;
}
GlobList &ClangTidyContext::getChecksFilter() {
@@ -328,7 +332,7 @@ 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));
+ HeaderFilter.reset(new llvm::Regex(*Context.getOptions().HeaderFilterRegex));
}
bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index 107a7817a6f..25bc6ed664b 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -117,9 +117,7 @@ struct ClangTidyStats {
class ClangTidyContext {
public:
/// \brief Initializes \c ClangTidyContext instance.
- ///
- /// Takes ownership of the \c OptionsProvider.
- ClangTidyContext(ClangTidyOptionsProvider *OptionsProvider);
+ ClangTidyContext(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider);
/// \brief Report any errors detected using this method.
///
@@ -180,6 +178,7 @@ private:
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider;
std::string CurrentFile;
+ ClangTidyOptions CurrentOptions;
std::unique_ptr<GlobList> CheckFilter;
ClangTidyStats Stats;
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index 9e4e33b58d6..33ce34ac320 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -8,7 +8,16 @@
//===----------------------------------------------------------------------===//
#include "ClangTidyOptions.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/YAMLTraits.h"
+#include <utility>
+
+#define DEBUG_TYPE "clang-tidy-options"
using clang::tidy::ClangTidyOptions;
using clang::tidy::FileFilter;
@@ -61,20 +70,134 @@ template <> struct MappingTraits<ClangTidyOptions> {
namespace clang {
namespace tidy {
+ClangTidyOptions
+ClangTidyOptions::mergeWith(const ClangTidyOptions &Other) const {
+ ClangTidyOptions Result = *this;
+
+ // Merge comma-separated glob lists by appending the new value after a comma.
+ if (Other.Checks)
+ Result.Checks =
+ (Result.Checks && !Result.Checks->empty() ? *Result.Checks + "," : "") +
+ *Other.Checks;
+
+ if (Other.HeaderFilterRegex)
+ Result.HeaderFilterRegex = Other.HeaderFilterRegex;
+ if (Other.AnalyzeTemporaryDtors)
+ Result.AnalyzeTemporaryDtors = Other.AnalyzeTemporaryDtors;
+ return Result;
+}
+
+FileOptionsProvider::FileOptionsProvider(
+ const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &FallbackOptions,
+ const ClangTidyOptions &OverrideOptions)
+ : DefaultOptionsProvider(GlobalOptions, FallbackOptions),
+ OverrideOptions(OverrideOptions) {
+ CachedOptions[""] = FallbackOptions.mergeWith(OverrideOptions);
+}
+
+static const char ConfigFileName[] = ".clang-tidy";
+
+// FIXME: This method has some common logic with clang::format::getStyle().
+// Consider pulling out common bits to a findParentFileWithName function or
+// similar.
+const ClangTidyOptions &FileOptionsProvider::getOptions(StringRef FileName) {
+ DEBUG(llvm::dbgs() << "Getting options for file " << FileName << "...\n");
+ SmallString<256> FilePath(FileName);
+
+ if (std::error_code EC = llvm::sys::fs::make_absolute(FilePath)) {
+ llvm::errs() << "Can't make absolute path from " << FileName << ": "
+ << EC.message() << "\n";
+ // FIXME: Figure out what to do.
+ } else {
+ FileName = FilePath;
+ }
+
+ // Look for a suitable configuration file in all parent directories of the
+ // file. Start with the immediate parent directory and move up.
+ StringRef Path = llvm::sys::path::parent_path(FileName);
+ for (StringRef CurrentPath = Path;;
+ CurrentPath = llvm::sys::path::parent_path(CurrentPath)) {
+ llvm::ErrorOr<ClangTidyOptions> Result = std::error_code();
+
+ auto Iter = CachedOptions.find(CurrentPath);
+ if (Iter != CachedOptions.end())
+ Result = Iter->second;
+
+ if (!Result)
+ Result = TryReadConfigFile(CurrentPath);
+
+ if (Result) {
+ // Store cached value for all intermediate directories.
+ while (Path != CurrentPath) {
+ DEBUG(llvm::dbgs() << "Caching configuration for path " << Path
+ << ".\n");
+ CachedOptions.GetOrCreateValue(Path, *Result);
+ Path = llvm::sys::path::parent_path(Path);
+ }
+ return CachedOptions.GetOrCreateValue(Path, *Result).getValue();
+ }
+ if (Result.getError() != std::errc::no_such_file_or_directory) {
+ llvm::errs() << "Error reading " << ConfigFileName << " from " << Path
+ << ": " << Result.getError().message() << "\n";
+ }
+ }
+}
+
+llvm::ErrorOr<ClangTidyOptions>
+FileOptionsProvider::TryReadConfigFile(StringRef Directory) {
+ assert(!Directory.empty());
+
+ ClangTidyOptions Options = DefaultOptionsProvider::getOptions(Directory);
+ if (!llvm::sys::fs::is_directory(Directory))
+ return std::errc::not_a_directory;
+
+ SmallString<128> ConfigFile(Directory);
+ llvm::sys::path::append(ConfigFile, ".clang-tidy");
+ DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n");
+
+ bool IsFile = false;
+ // Ignore errors from is_regular_file: we only need to know if we can read
+ // the file or not.
+ llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile);
+
+ if (!IsFile)
+ return std::errc::no_such_file_or_directory;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
+ llvm::MemoryBuffer::getFile(ConfigFile.c_str());
+ if (std::error_code EC = Text.getError())
+ return EC;
+ if (std::error_code EC = parseConfiguration((*Text)->getBuffer(), Options))
+ return EC;
+ return Options.mergeWith(OverrideOptions);
+}
+
/// \brief Parses -line-filter option and stores it to the \c Options.
-std::error_code parseLineFilter(const std::string &LineFilter,
+std::error_code parseLineFilter(StringRef LineFilter,
clang::tidy::ClangTidyGlobalOptions &Options) {
llvm::yaml::Input Input(LineFilter);
Input >> Options.LineFilter;
return Input.error();
}
-std::error_code parseConfiguration(const std::string &Config,
+std::error_code parseConfiguration(StringRef Config,
clang::tidy::ClangTidyOptions &Options) {
llvm::yaml::Input Input(Config);
Input >> Options;
return Input.error();
}
+std::string configurationAsText(const ClangTidyOptions &Options) {
+ std::string Text;
+ llvm::raw_string_ostream Stream(Text);
+ llvm::yaml::Output Output(Stream);
+ // We use the same mapping method for input and output, so we need a non-const
+ // reference here.
+ ClangTidyOptions NonConstValue = Options;
+ Output << NonConstValue;
+ return Stream.str();
+}
+
} // namespace tidy
} // namespace clang
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index 2354c93c621..14b23ae2719 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -10,7 +10,10 @@
#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/Optional.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorOr.h"
#include <string>
#include <system_error>
#include <utility>
@@ -42,18 +45,31 @@ struct ClangTidyGlobalOptions {
/// \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 These options are used for all settings that haven't been
+ /// overridden by the \c OptionsProvider.
+ ///
+ /// Allow no checks and no headers by default.
+ static ClangTidyOptions getDefaults() {
+ ClangTidyOptions Options;
+ Options.Checks = "";
+ Options.HeaderFilterRegex = "";
+ Options.AnalyzeTemporaryDtors = false;
+ return Options;
+ }
+
+ /// \brief Creates a new \c ClangTidyOptions instance combined from all fields
+ /// of this instance overridden by the fields of \p Other that have a value.
+ ClangTidyOptions mergeWith(const ClangTidyOptions &Other) const;
/// \brief Checks filter.
- std::string Checks;
+ llvm::Optional<std::string> Checks;
/// \brief Output warnings from headers matching this filter. Warnings from
/// main files will always be displayed.
- std::string HeaderFilterRegex;
+ llvm::Optional<std::string> HeaderFilterRegex;
/// \brief Turns on temporary destructor-based analysis.
- bool AnalyzeTemporaryDtors;
+ llvm::Optional<bool> AnalyzeTemporaryDtors;
};
/// \brief Abstract interface for retrieving various ClangTidy options.
@@ -79,7 +95,7 @@ public:
const ClangTidyGlobalOptions &getGlobalOptions() override {
return GlobalOptions;
}
- const ClangTidyOptions &getOptions(llvm::StringRef) override {
+ const ClangTidyOptions &getOptions(llvm::StringRef /*FileName*/) override {
return DefaultOptions;
}
@@ -88,13 +104,45 @@ private:
ClangTidyOptions DefaultOptions;
};
+/// \brief Implementation of the \c ClangTidyOptionsProvider interface, which
+/// tries to find a .clang-tidy file in the closest parent directory of each
+/// file.
+class FileOptionsProvider : public DefaultOptionsProvider {
+public:
+ /// \brief Initializes the \c FileOptionsProvider instance.
+ ///
+ /// \param GlobalOptions are just stored and returned to the caller of
+ /// \c getGlobalOptions.
+ ///
+ /// \param FallbackOptions are used in case there's no corresponding
+ /// .clang-tidy file.
+ ///
+ /// If any of the \param OverrideOptions fields are set, they will override
+ /// whatever options are read from the configuration file.
+ FileOptionsProvider(const ClangTidyGlobalOptions &GlobalOptions,
+ const ClangTidyOptions &FallbackOptions,
+ const ClangTidyOptions &OverrideOptions);
+ const ClangTidyOptions &getOptions(llvm::StringRef FileName) override;
+
+private:
+ /// \brief Try to read configuration file from \p Directory. If \p Directory
+ /// is empty, use the fallback value.
+ llvm::ErrorOr<ClangTidyOptions> TryReadConfigFile(llvm::StringRef Directory);
+
+ llvm::StringMap<ClangTidyOptions> CachedOptions;
+ ClangTidyOptions OverrideOptions;
+};
+
/// \brief Parses LineFilter from JSON and stores it to the \p Options.
-std::error_code parseLineFilter(const std::string &LineFilter,
- clang::tidy::ClangTidyGlobalOptions &Options);
+std::error_code parseLineFilter(llvm::StringRef LineFilter,
+ ClangTidyGlobalOptions &Options);
/// \brief Parses configuration from JSON and stores it to the \p Options.
-std::error_code parseConfiguration(const std::string &Config,
- clang::tidy::ClangTidyOptions &Options);
+std::error_code parseConfiguration(llvm::StringRef Config,
+ ClangTidyOptions &Options);
+
+/// \brief Serializes configuration to a YAML-encoded string.
+std::string configurationAsText(const ClangTidyOptions &Options);
} // end namespace tidy
} // end namespace clang
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index d49994d2f41..6048217f3dc 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -26,6 +26,13 @@ using namespace llvm;
static cl::OptionCategory ClangTidyCategory("clang-tidy options");
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static cl::extrahelp ClangTidyHelp(
+ "Configuration files:\n"
+ " clang-tidy attempts to read configuration for each source file from a\n"
+ " .clang-tidy file located in the closest parent directory of the source\n"
+ " file. If any configuration options have a corresponding command-line\n"
+ " option, command-line option takes precedence. The effective\n"
+ " configuration can be inspected using -dump-config.\n\n");
const char DefaultChecks[] =
"*," // Enable all checks, except these:
@@ -39,7 +46,9 @@ Checks("checks", cl::desc("Comma-separated list of globs with optional '-'\n"
"in the list. Globs without '-' prefix add checks\n"
"with matching names to the set, globs with the '-'\n"
"prefix remove checks with matching names from the\n"
- "set of enabled checks."),
+ "set of enabled checks.\n"
+ "This option's value is appended to the value read\n"
+ "from a .clang-tidy file, if any."),
cl::init(""), cl::cat(ClangTidyCategory));
static cl::opt<std::string>
@@ -48,7 +57,9 @@ HeaderFilter("header-filter",
"headers to output diagnostics from. Diagnostics\n"
"from the main file of each translation unit are\n"
"always displayed.\n"
- "Can be used together with -line-filter."),
+ "Can be used together with -line-filter.\n"
+ "This option overrides the value read from a\n"
+ ".clang-tidy file."),
cl::init(""), cl::cat(ClangTidyCategory));
static cl::opt<std::string>
@@ -73,10 +84,17 @@ ListChecks("list-checks",
cl::init(false), cl::cat(ClangTidyCategory));
static cl::opt<bool>
-AnalyzeTemporaryDtors("analyze-temporary-dtors",
- cl::desc("Enable temporary destructor-aware analysis in\n"
- "clang-analyzer- checks."),
- cl::init(false), cl::cat(ClangTidyCategory));
+DumpConfig("dump-config",
+ cl::desc("Dumps configuration in the YAML format to stdout."),
+ cl::init(false), cl::cat(ClangTidyCategory));
+
+static cl::opt<bool> AnalyzeTemporaryDtors(
+ "analyze-temporary-dtors",
+ cl::desc("Enable temporary destructor-aware analysis in\n"
+ "clang-analyzer- checks.\n"
+ "This option overrides the value read from a\n"
+ ".clang-tidy file."),
+ cl::init(false), cl::cat(ClangTidyCategory));
static cl::opt<std::string> ExportFixes(
"export-fixes",
@@ -123,12 +141,25 @@ int main(int argc, const char **argv) {
return 1;
}
- clang::tidy::ClangTidyOptions Options;
- Options.Checks = DefaultChecks + Checks;
- Options.HeaderFilterRegex = HeaderFilter;
- Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+ clang::tidy::ClangTidyOptions FallbackOptions;
+ FallbackOptions.Checks = DefaultChecks;
+ FallbackOptions.HeaderFilterRegex = HeaderFilter;
+ FallbackOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+
+ clang::tidy::ClangTidyOptions OverrideOptions;
+ if (Checks.getNumOccurrences() > 0)
+ OverrideOptions.Checks = Checks;
+ if (HeaderFilter.getNumOccurrences() > 0)
+ OverrideOptions.HeaderFilterRegex = HeaderFilter;
+ if (AnalyzeTemporaryDtors.getNumOccurrences() > 0)
+ OverrideOptions.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+
+ auto OptionsProvider = llvm::make_unique<clang::tidy::FileOptionsProvider>(
+ GlobalOptions, FallbackOptions, OverrideOptions);
- std::vector<std::string> EnabledChecks = clang::tidy::getCheckNames(Options);
+ std::string FileName = OptionsParser.getSourcePathList().front();
+ std::vector<std::string> EnabledChecks =
+ clang::tidy::getCheckNames(OptionsProvider->getOptions(FileName));
// FIXME: Allow using --list-checks without positional arguments.
if (ListChecks) {
@@ -139,18 +170,23 @@ int main(int argc, const char **argv) {
return 0;
}
+ if (DumpConfig) {
+ llvm::outs() << clang::tidy::configurationAsText(
+ clang::tidy::ClangTidyOptions::getDefaults()
+ .mergeWith(OptionsProvider->getOptions(FileName)))
+ << "\n";
+ return 0;
+ }
+
if (EnabledChecks.empty()) {
llvm::errs() << "Error: no checks enabled.\n";
llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
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(
- OptionsProvider, OptionsParser.getCompilations(),
+ std::move(OptionsProvider), OptionsParser.getCompilations(),
OptionsParser.getSourcePathList(), &Errors);
clang::tidy::handleErrors(Errors, Fix);
diff --git a/clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy b/clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy
new file mode 100644
index 00000000000..942169f2ec4
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/Inputs/config-files/.clang-tidy
@@ -0,0 +1,2 @@
+Checks: 'from-parent'
+HeaderFilterRegex: 'parent'
diff --git a/clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy b/clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy
new file mode 100644
index 00000000000..800fd4e8eb2
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/Inputs/config-files/1/.clang-tidy
@@ -0,0 +1,2 @@
+Checks: 'from-child1'
+HeaderFilterRegex: 'child1'
diff --git a/clang-tools-extra/test/clang-tidy/config-files.cpp b/clang-tools-extra/test/clang-tidy/config-files.cpp
new file mode 100644
index 00000000000..ec3904d6f9e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/config-files.cpp
@@ -0,0 +1,12 @@
+// RUN: clang-tidy -dump-config %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-BASE
+// CHECK-BASE: Checks: from-parent
+// CHECK-BASE: HeaderFilterRegex: parent
+// RUN: clang-tidy -dump-config %S/Inputs/config-files/1/- -- | FileCheck %s -check-prefix=CHECK-CHILD1
+// CHECK-CHILD1: Checks: from-child1
+// CHECK-CHILD1: HeaderFilterRegex: child1
+// RUN: clang-tidy -dump-config %S/Inputs/config-files/2/- -- | FileCheck %s -check-prefix=CHECK-CHILD2
+// CHECK-CHILD2: Checks: from-parent
+// CHECK-CHILD2: HeaderFilterRegex: parent
+// RUN: clang-tidy -dump-config -checks='from-command-line' -header-filter='from command line' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-COMMAND-LINE
+// CHECK-COMMAND-LINE: Checks: from-parent,from-command-line
+// CHECK-COMMAND-LINE: HeaderFilterRegex: from command line
diff --git a/clang-tools-extra/test/clang-tidy/diagnostic.cpp b/clang-tools-extra/test/clang-tidy/diagnostic.cpp
index 406ec83d5d9..b223fb7762a 100644
--- a/clang-tools-extra/test/clang-tidy/diagnostic.cpp
+++ b/clang-tools-extra/test/clang-tidy/diagnostic.cpp
@@ -1,5 +1,5 @@
// RUN: clang-tidy -checks='-*,misc-use-override' %s.nonexistent.cpp -- | FileCheck -check-prefix=CHECK1 %s
-// RUN: clang-tidy -checks='-google-*,google-explicit-constructor' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK2 %s
+// RUN: clang-tidy -checks='-*,clang-diagnostic-*,google-explicit-constructor' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK2 %s
// RUN: clang-tidy -checks='-*,google-explicit-constructor,clang-diagnostic-literal-conversion' %s -- -fan-unknown-option | FileCheck -check-prefix=CHECK3 %s
// RUN: clang-tidy -checks='-*,misc-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE | FileCheck -check-prefix=CHECK4 %s
diff --git a/clang-tools-extra/test/clang-tidy/validate-check-names.cpp b/clang-tools-extra/test/clang-tidy/validate-check-names.cpp
new file mode 100644
index 00000000000..709d9deb20d
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/validate-check-names.cpp
@@ -0,0 +1,2 @@
+// Check names may only contain alphanumeric characters, '-', '_', and '.'.
+// RUN: clang-tidy -checks=* -list-checks - -- | grep '^ ' | cut -b5- | not grep -v '^[a-zA-Z0-9_.\-]\+$'
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
index 55d8a6dadad..8b0fbc6ff75 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyOptionsTest.cpp
@@ -61,9 +61,9 @@ TEST(ParseConfiguration, ValidConfiguration) {
"AnalyzeTemporaryDtors: true\n",
Options);
EXPECT_FALSE(Error);
- EXPECT_EQ("-*,misc-*", Options.Checks);
- EXPECT_EQ(".*", Options.HeaderFilterRegex);
- EXPECT_TRUE(Options.AnalyzeTemporaryDtors);
+ EXPECT_EQ("-*,misc-*", *Options.Checks);
+ EXPECT_EQ(".*", *Options.HeaderFilterRegex);
+ EXPECT_TRUE(*Options.AnalyzeTemporaryDtors);
}
} // namespace test
diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
index a9c68d4a939..ffadc1f00f7 100644
--- a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
+++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h
@@ -45,8 +45,10 @@ std::string runCheckOnCode(StringRef Code,
const Twine &Filename = "input.cc",
ArrayRef<std::string> ExtraArgs = None) {
T Check;
- ClangTidyContext Context(
- new DefaultOptionsProvider(ClangTidyGlobalOptions(), ClangTidyOptions()));
+ ClangTidyOptions Options;
+ Options.Checks = "*";
+ ClangTidyContext Context(llvm::make_unique<DefaultOptionsProvider>(
+ ClangTidyGlobalOptions(), Options));
ClangTidyDiagnosticConsumer DiagConsumer(Context);
Check.setContext(&Context);
std::vector<std::string> ArgCXX11(1, "-std=c++11");
OpenPOWER on IntegriCloud