From 60fce8273c8aa07369de84ce2ea80889aefd3963 Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Thu, 24 Mar 2016 10:50:17 +0000 Subject: [PATCH] Added support for different VFSs in format::getStyle. Summary: Previously, format::getStyle assumes that the given file resides in the real file system, which prevents the use of virtual file system in testing etc. This patch adds a parameter in format::getStyle interface so that users can specify the right file system. By default, the file system is the real file system. Reviewers: djasper, klimek Subscribers: cfe-commits, klimek Differential Revision: http://reviews.llvm.org/D18399 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@264253 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Format/Format.h | 5 ++++- lib/Format/Format.cpp | 24 +++++++++++++++++------- unittests/Format/FormatTest.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index eef651e636..650da68097 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_FORMAT_FORMAT_H #include "clang/Basic/LangOptions.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/ArrayRef.h" #include @@ -832,11 +833,13 @@ extern const char *StyleOptionHelpDescription; /// == "file". /// \param[in] FallbackStyle The name of a predefined style used to fallback to /// in case the style can't be determined from \p StyleName. +/// \param[in] FS The underlying file system, in which the file resides. By +/// default, the file system is the real file system. /// /// \returns FormatStyle as specified by ``StyleName``. If no style could be /// determined, the default is LLVM Style (see ``getLLVMStyle()``). FormatStyle getStyle(StringRef StyleName, StringRef FileName, - StringRef FallbackStyle); + StringRef FallbackStyle, vfs::FileSystem *FS = nullptr); } // end namespace format } // end namespace clang diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 31dc259d4c..6d03b62920 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -2099,7 +2099,10 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { } FormatStyle getStyle(StringRef StyleName, StringRef FileName, - StringRef FallbackStyle) { + StringRef FallbackStyle, vfs::FileSystem *FS) { + if (!FS) { + FS = vfs::getRealFileSystem().get(); + } FormatStyle Style = getLLVMStyle(); Style.Language = getLanguageByFileName(FileName); if (!getPredefinedStyle(FallbackStyle, Style.Language, &Style)) { @@ -2130,28 +2133,35 @@ FormatStyle getStyle(StringRef StyleName, StringRef FileName, llvm::sys::fs::make_absolute(Path); for (StringRef Directory = Path; !Directory.empty(); Directory = llvm::sys::path::parent_path(Directory)) { - if (!llvm::sys::fs::is_directory(Directory)) + + auto Status = FS->status(Directory); + if (!Status || + Status->getType() != llvm::sys::fs::file_type::directory_file) { continue; + } + SmallString<128> ConfigFile(Directory); llvm::sys::path::append(ConfigFile, ".clang-format"); 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); - + Status = FS->status(ConfigFile.str()); + bool IsFile = + Status && (Status->getType() == llvm::sys::fs::file_type::regular_file); if (!IsFile) { // Try _clang-format too, since dotfiles are not commonly used on Windows. ConfigFile = Directory; llvm::sys::path::append(ConfigFile, "_clang-format"); DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n"); - llvm::sys::fs::is_regular_file(Twine(ConfigFile), IsFile); + Status = FS->status(ConfigFile.str()); + IsFile = Status && + (Status->getType() == llvm::sys::fs::file_type::regular_file); } if (IsFile) { llvm::ErrorOr> Text = - llvm::MemoryBuffer::getFile(ConfigFile.c_str()); + FS->getBufferForFile(ConfigFile.str()); if (std::error_code EC = Text.getError()) { llvm::errs() << EC.message() << "\n"; break; diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index d2ec4e645c..319f63ded5 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -14,6 +14,7 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/MemoryBuffer.h" #include "gtest/gtest.h" #define DEBUG_TYPE "format-test" @@ -11199,6 +11200,33 @@ TEST_F(FormatTest, FormatsTableGenCode) { verifyFormat("include \"a.td\"\ninclude \"b.td\"", Style); } +TEST(FormatStyle, GetStyleOfFile) { + vfs::InMemoryFileSystem FS; + // Test 1: format file in the same directory. + ASSERT_TRUE( + FS.addFile("/a/.clang-format", 0, + llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: LLVM"))); + ASSERT_TRUE( + FS.addFile("/a/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;"))); + auto Style1 = getStyle("file", "/a/.clang-format", "Google", &FS); + ASSERT_EQ(Style1, getLLVMStyle()); + + // Test 2: fallback to default. + ASSERT_TRUE( + FS.addFile("/b/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;"))); + auto Style2 = getStyle("file", "/b/test.cpp", "Mozilla", &FS); + ASSERT_EQ(Style2, getMozillaStyle()); + + // Test 3: format file in parent directory. + ASSERT_TRUE( + FS.addFile("/c/.clang-format", 0, + llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google"))); + ASSERT_TRUE(FS.addFile("/c/sub/sub/sub/test.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("int i;"))); + auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", "LLVM", &FS); + ASSERT_EQ(Style3, getGoogleStyle()); +} + class ReplacementTest : public ::testing::Test { protected: tooling::Replacement createReplacement(SourceLocation Start, unsigned Length, -- 2.40.0