Implemented clang-tidy-check-specific options.

Summary:
Each check can implement readOptions and storeOptions methods to read
and store custom options. Each check's options are stored in a local namespace
to avoid name collisions and provide some sort of context to the user.

Reviewers: bkramer, klimek

Reviewed By: klimek

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D5296

llvm-svn: 217661
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
index e4ceb9c..0cc82e8 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
@@ -25,6 +25,7 @@
 
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter::LineRange)
+LLVM_YAML_IS_SEQUENCE_VECTOR(ClangTidyOptions::StringPair);
 
 namespace llvm {
 namespace yaml {
@@ -57,11 +58,34 @@
   }
 };
 
+template <> struct MappingTraits<ClangTidyOptions::StringPair> {
+  static void mapping(IO &IO, ClangTidyOptions::StringPair &KeyValue) {
+    IO.mapRequired("key", KeyValue.first);
+    IO.mapRequired("value", KeyValue.second);
+  }
+};
+
+struct NOptionMap {
+  NOptionMap(IO &) {}
+  NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap)
+      : Options(OptionMap.begin(), OptionMap.end()) {}
+  ClangTidyOptions::OptionMap denormalize(IO &) {
+    ClangTidyOptions::OptionMap Map;
+    for (const auto &KeyValue : Options)
+      Map[KeyValue.first] = KeyValue.second;
+    return Map;
+  }
+  std::vector<ClangTidyOptions::StringPair> Options;
+};
+
 template <> struct MappingTraits<ClangTidyOptions> {
   static void mapping(IO &IO, ClangTidyOptions &Options) {
+    MappingNormalization<NOptionMap, ClangTidyOptions::OptionMap> NOpts(
+        IO, Options.CheckOptions);
     IO.mapOptional("Checks", Options.Checks);
     IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex);
     IO.mapOptional("AnalyzeTemporaryDtors", Options.AnalyzeTemporaryDtors);
+    IO.mapOptional("CheckOptions", NOpts->Options);
   }
 };
 
@@ -85,6 +109,10 @@
     Result.HeaderFilterRegex = Other.HeaderFilterRegex;
   if (Other.AnalyzeTemporaryDtors)
     Result.AnalyzeTemporaryDtors = Other.AnalyzeTemporaryDtors;
+
+  for (const auto &KeyValue : Other.CheckOptions)
+    Result.CheckOptions[KeyValue.first] = KeyValue.second;
+
   return Result;
 }
 
@@ -169,6 +197,10 @@
       llvm::MemoryBuffer::getFile(ConfigFile.c_str());
   if (std::error_code EC = Text.getError())
     return EC;
+  // Skip empty files, e.g. files opened for writing via shell output
+  // redirection.
+  if ((*Text)->getBuffer().empty())
+    return make_error_code(llvm::errc::no_such_file_or_directory);
   if (std::error_code EC = parseConfiguration((*Text)->getBuffer(), Options))
     return EC;
   return Options.mergeWith(OverrideOptions);