summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
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 /clang-tools-extra/clang-tidy/ClangTidyOptions.cpp
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
Diffstat (limited to 'clang-tools-extra/clang-tidy/ClangTidyOptions.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidyOptions.cpp127
1 files changed, 125 insertions, 2 deletions
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
OpenPOWER on IntegriCloud