diff options
| author | Alexander Kornienko <alexfh@google.com> | 2014-09-04 14:23:36 +0000 |
|---|---|---|
| committer | Alexander Kornienko <alexfh@google.com> | 2014-09-04 14:23:36 +0000 |
| commit | d53d2686b31f83143a28d53135daaef595f396de (patch) | |
| tree | 0c37c13cec880e2ea57f1b4fee749c2f5ce58325 /clang-tools-extra/clang-tidy/ClangTidyOptions.cpp | |
| parent | c0ae1a038f67fdbd79843d26c42b943b1111cd08 (diff) | |
| download | bcm5719-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.cpp | 127 |
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 |

