diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -325,7 +325,9 @@ FileOptionsBaseProvider::tryReadConfigFile(StringRef Directory) { assert(!Directory.empty()); - if (!llvm::sys::fs::is_directory(Directory)) { + llvm::ErrorOr DirectoryStatus = FS->status(Directory); + + if (!DirectoryStatus || !DirectoryStatus->isDirectory()) { llvm::errs() << "Error reading configuration from " << Directory << ": directory doesn't exist.\n"; return llvm::None; @@ -336,15 +338,13 @@ llvm::sys::path::append(ConfigFile, ConfigHandler.first); LLVM_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) + llvm::ErrorOr FileStatus = FS->status(ConfigFile); + + if (!FileStatus || !FileStatus->isRegularFile()) continue; llvm::ErrorOr> Text = - llvm::MemoryBuffer::getFile(ConfigFile.c_str()); + FS->getBufferForFile(ConfigFile); if (std::error_code EC = Text.getError()) { llvm::errs() << "Can't read " << ConfigFile << ": " << EC.message() << "\n"; @@ -363,7 +363,7 @@ << ParsedOptions.getError().message() << "\n"; continue; } - return OptionsSource(*ParsedOptions, ConfigFile.c_str()); + return OptionsSource(*ParsedOptions, ConfigFile.str()); } return llvm::None; } diff --git a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt --- a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt @@ -17,6 +17,7 @@ LLVMModuleTest.cpp NamespaceAliaserTest.cpp ObjCModuleTest.cpp + OptionsProviderTest.cpp OverlappingReplacementsTest.cpp UsingInserterTest.cpp ReadabilityModuleTest.cpp diff --git a/clang-tools-extra/unittests/clang-tidy/OptionsProviderTest.cpp b/clang-tools-extra/unittests/clang-tidy/OptionsProviderTest.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/unittests/clang-tidy/OptionsProviderTest.cpp @@ -0,0 +1,67 @@ +//===---- ObjCModuleTest.cpp - clang-tidy ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ClangTidyOptions.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "gtest/gtest.h" + +namespace clang { +namespace tidy { +namespace test { + +TEST(ClangTidyOptionsProvider, InMemoryFileSystems) { + llvm::IntrusiveRefCntPtr FileSystem( + new llvm::vfs::InMemoryFileSystem); + + StringRef BaseClangTidy = R"( + Checks: -*,clang-diagnostic-* + )"; + StringRef Sub1ClangTidy = R"( + Checks: readability-* + InheritParentConfig: true + )"; + StringRef Sub2ClangTidy = R"( + Checks: bugprone-*,misc-*,clang-diagnostic-* + InheritParentConfig: false + )"; + FileSystem->addFile("ProjectRoot/.clang-tidy", 0, + llvm::MemoryBuffer::getMemBuffer(BaseClangTidy)); + FileSystem->addFile("ProjectRoot/SubDir1/.clang-tidy", 0, + llvm::MemoryBuffer::getMemBuffer(Sub1ClangTidy)); + FileSystem->addFile("ProjectRoot/SubDir1/File.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("")); + FileSystem->addFile("ProjectRoot/SubDir1/SubDir2/.clang-tidy", 0, + llvm::MemoryBuffer::getMemBuffer(Sub2ClangTidy)); + FileSystem->addFile("ProjectRoot/SubDir1/SubDir2/File.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("")); + FileSystem->addFile("ProjectRoot/SubDir1/SubDir2/SubDir3/File.cpp", 0, + llvm::MemoryBuffer::getMemBuffer("")); + + FileOptionsProvider FileOpt({}, {}, {}, FileSystem); + + ClangTidyOptions File1Options = + FileOpt.getOptions("ProjectRoot/SubDir1/File.cpp"); + ClangTidyOptions File2Options = + FileOpt.getOptions("ProjectRoot/SubDir1/SubDir2/File.cpp"); + ClangTidyOptions File3Options = + FileOpt.getOptions("ProjectRoot/SubDir1/SubDir2/SubDir3/File.cpp"); + + ASSERT_TRUE(File1Options.Checks.hasValue()); + EXPECT_EQ(*File1Options.Checks, "-*,clang-diagnostic-*,readability-*"); + ASSERT_TRUE(File2Options.Checks.hasValue()); + EXPECT_EQ(*File2Options.Checks, "bugprone-*,misc-*,clang-diagnostic-*"); + + // 2 and 3 should use the same config so these should also be the same. + EXPECT_EQ(File2Options.Checks, File3Options.Checks); +} + +} // namespace test +} // namespace tidy +} // namespace clang \ No newline at end of file