[clang] [clang-tools-extra] [llvm] [clang-format] Add support for BasedOnStyle referencing an arbitrary file (PR #107312)

Ryan Saunders via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 4 14:00:59 PDT 2024


https://github.com/jediry created https://github.com/llvm/llvm-project/pull/107312

At present, the ```BasedOnStyle``` directive can reference a predefined style name, or ```InheritFromParent```, instructing clang-format to search upward in the directory hierarchy for a .clang-format file. This works fine when variations in codebase formatting align with the directory hierarchy, but becomes problematic when it is desired to share formatting across portions of a repository with no common parent directory. For example, consider the case of a large, multi-team repository containing many projects as sub-directories of the repository root, where each of the various engineering teams owns multiple of these projects, and wants a common coding style across all of its owned projects.

In this PR, I'm extending ```BasedOnStyle``` to allow referencing an arbitrary file. While this could be an absolute path, that's not typically useful across machines. In typical usage, this will be a relative path (e.g., ```BasedOnStyle: format/team1.clang-format```).  For resolving relative paths, I've mimicked the "include path" model of C/C++ (and, in fact, I'm able to leverage ```SourceMgr```'s "include paths" mechanism to implement this). The list of style search paths is specified on the command-line via one or more ```--style-search-path <path>``` parameters.

The interesting stuff is in Format.cpp...most of the rest of this change is plumbing to get the StyleSearchPaths from the command-line to the call to ```getStyle()```.

Unfinished aspects of this change:
* No unit tests. I am happy to write some, but I'm unsure how to do this in a harmonious way, seeing as my change inherently relies on external files on the filesystem. Most of the unit tests I've seen in Clang rely on in-code strings.
* ```--style-search-path .``` does not seem to work for specifying the current directory as a search path. Evidently the ```SourceMgr``` include paths mechanism does not handle this natively. Can someone point me to the proper "Clang" way to resolve paths like . or .. into paths that ```SourceMgr``` can handle?

>From 163657095741b2292540fce7ff424cb4600391da Mon Sep 17 00:00:00 2001
From: Ryan Saunders <ryansaun at microsoft.com>
Date: Fri, 2 Aug 2024 15:08:24 -0700
Subject: [PATCH] Add support for BasedOnStyle referencing an arbitrary file,
 locatable relative to directories specified via --style-search-path

Improve command-line help

Clean up formatting

Fix unit tests

Fix other clang tools that leverage format::getStyle()

Fix up clangd
---
 .../tool/ClangApplyReplacementsMain.cpp       |  19 ++++
 .../ChangeNamespace.cpp                       |   7 +-
 .../clang-change-namespace/ChangeNamespace.h  |   6 +-
 .../tool/ClangChangeNamespace.cpp             |  18 ++-
 .../tool/ClangIncludeFixer.cpp                |  22 +++-
 clang-tools-extra/clang-move/Move.cpp         |   1 +
 clang-tools-extra/clang-move/Move.h           |   3 +
 .../clang-move/tool/ClangMove.cpp             |  22 +++-
 clang-tools-extra/clang-tidy/ClangTidy.cpp    |   3 +-
 .../clang-tidy/ClangTidyOptions.h             |   4 +
 .../clang-tidy/misc/IncludeCleanerCheck.cpp   |   5 +-
 .../clang-tidy/misc/IncludeCleanerCheck.h     |   1 +
 .../clang-tidy/tool/ClangTidyMain.cpp         |  15 +++
 clang-tools-extra/clangd/ClangdLSPServer.cpp  |   2 +-
 clang-tools-extra/clangd/ClangdServer.cpp     |  13 ++-
 clang-tools-extra/clangd/ClangdServer.h       |  11 +-
 clang-tools-extra/clangd/Config.h             |   4 +
 clang-tools-extra/clangd/IncludeCleaner.cpp   |   1 +
 clang-tools-extra/clangd/SourceCode.cpp       |   3 +
 clang-tools-extra/clangd/tool/Check.cpp       |   2 +-
 clang-tools-extra/clangd/tool/ClangdMain.cpp  |  23 ++++
 .../clangd/unittests/ClangdTests.cpp          |   2 +-
 .../include-cleaner/tool/IncludeCleaner.cpp   |  15 ++-
 .../ChangeNamespaceTests.cpp                  |   2 +-
 .../unittests/clang-move/ClangMoveTests.cpp   |   4 +-
 clang/include/clang/Format/Format.h           |  29 ++++-
 clang/include/clang/Tooling/Refactoring.h     |   4 +-
 clang/lib/Format/Format.cpp                   |  51 +++++++--
 clang/lib/Tooling/Refactoring.cpp             |   4 +-
 clang/tools/clang-format/ClangFormat.cpp      |  21 +++-
 clang/unittests/Format/ConfigParseTest.cpp    | 106 ++++++++++--------
 clang/unittests/Format/FormatTestObjC.cpp     |  56 ++++-----
 .../unittests/Format/FormatTestRawStrings.cpp |   2 +-
 .../ObjCPropertyAttributeOrderFixerTest.cpp   |   6 +-
 clang/unittests/Format/QualifierFixerTest.cpp |   6 +-
 clang/unittests/Rename/ClangRenameTest.h      |   2 +-
 clang/unittests/Tooling/RefactoringTest.cpp   |   3 +-
 llvm/include/llvm/Support/YAMLTraits.h        |   6 +
 llvm/lib/Support/YAMLTraits.cpp               |  12 ++
 39 files changed, 391 insertions(+), 125 deletions(-)

diff --git a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
index 68b5743c6540f8..52e1251cb1482a 100644
--- a/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
+++ b/clang-tools-extra/clang-apply-replacements/tool/ClangApplyReplacementsMain.cpp
@@ -69,6 +69,24 @@ static cl::opt<std::string>
     FormatStyleOpt("style", cl::desc(format::StyleOptionHelpDescription),
                    cl::init("LLVM"), cl::cat(FormattingCategory));
 
+static cl::list<std::string>
+StyleSearchPaths(
+    "style-search-path",
+    cl::desc("Directory to search for BasedOnStyle files, when the value of the\n"
+             "BasedOnStyle directive is not one of the predefined styles, nor\n"
+             "InheritFromParent. Multiple style search paths may be specified,\n"
+             "and will be searched in order, stopping at the first file found."),
+    cl::value_desc("directory"),
+    cl::cat(FormattingCategory));
+
+static cl::alias
+StyleSearchPathShort(
+    "S",
+    cl::desc("Alias for --style-search-path"),
+    cl::cat(FormattingCategory),
+    cl::aliasopt(StyleSearchPaths),
+    cl::NotHidden);
+
 namespace {
 // Helper object to remove the TUReplacement and TUDiagnostic (triggered by
 // "remove-change-desc-files" command line option) when exiting current scope.
@@ -102,6 +120,7 @@ int main(int argc, char **argv) {
 
   // Determine a formatting style from options.
   auto FormatStyleOrError = format::getStyle(FormatStyleOpt, FormatStyleConfig,
+                                             StyleSearchPaths,
                                              format::DefaultFallbackStyle);
   if (!FormatStyleOrError) {
     llvm::errs() << llvm::toString(FormatStyleOrError.takeError()) << "\n";
diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
index 879c0d26d472a8..f1a4716e2c45ea 100644
--- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp
@@ -339,8 +339,9 @@ ChangeNamespaceTool::ChangeNamespaceTool(
     llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
     llvm::ArrayRef<std::string> AllowedSymbolPatterns,
     std::map<std::string, tooling::Replacements> *FileToReplacements,
-    llvm::StringRef FallbackStyle)
-    : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
+    llvm::StringRef FallbackStyle, const std::vector<std::string>& StyleSearchPaths)
+    : FallbackStyle(FallbackStyle), StyleSearchPaths(StyleSearchPaths),
+      FileToReplacements(*FileToReplacements),
       OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
       FilePattern(FilePattern), FilePatternRE(FilePattern) {
   FileToReplacements->clear();
@@ -1004,7 +1005,7 @@ void ChangeNamespaceTool::onEndOfTranslationUnit() {
     // which refers to the original code.
     Replaces = Replaces.merge(NewReplacements);
     auto Style =
-        format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
+        format::getStyle(format::DefaultFormatStyle, FilePath, StyleSearchPaths, FallbackStyle);
     if (!Style) {
       llvm::errs() << llvm::toString(Style.takeError()) << "\n";
       continue;
diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.h b/clang-tools-extra/clang-change-namespace/ChangeNamespace.h
index d35119b70a69c4..969d983681ebd5 100644
--- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.h
+++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.h
@@ -51,7 +51,8 @@ class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {
       llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
       llvm::ArrayRef<std::string> AllowedSymbolPatterns,
       std::map<std::string, tooling::Replacements> *FileToReplacements,
-      llvm::StringRef FallbackStyle = "LLVM");
+      llvm::StringRef FallbackStyle = "LLVM",
+      const std::vector<std::string>& StyleSearchPaths = {});
 
   void registerMatchers(ast_matchers::MatchFinder *Finder);
 
@@ -109,6 +110,9 @@ class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {
   };
 
   std::string FallbackStyle;
+  // Specifies the list of paths to be searched when FormatStyle or a BasedOnStyle
+  // in a .clang-format file specifies an arbitrary file to include
+  std::vector<std::string> StyleSearchPaths;
   // In match callbacks, this contains replacements for replacing `typeLoc`s in
   // and deleting forward declarations in the moved namespace blocks.
   // In `onEndOfTranslationUnit` callback, the previous added replacements are
diff --git a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
index 22d26db0c11bcf..b78dcfc713a037 100644
--- a/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
+++ b/clang-tools-extra/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -72,6 +72,22 @@ cl::opt<std::string> Style("style",
                            cl::desc("The style name used for reformatting."),
                            cl::init("LLVM"), cl::cat(ChangeNamespaceCategory));
 
+cl::list<std::string> StyleSearchPaths(
+    "style-search-path",
+    cl::desc("Directory to search for BasedOnStyle files, when the value of the\n"
+             "BasedOnStyle directive is not one of the predefined styles, nor\n"
+             "InheritFromParent. Multiple style search paths may be specified,\n"
+             "and will be searched in order, stopping at the first file found."),
+    cl::value_desc("directory"),
+    cl::cat(ChangeNamespaceCategory));
+
+cl::alias StyleSearchPathShort(
+    "S",
+    cl::desc("Alias for --style-search-path"),
+    cl::cat(ChangeNamespaceCategory),
+    cl::aliasopt(StyleSearchPaths),
+    cl::NotHidden);
+
 cl::opt<std::string> AllowedFile(
     "allowed_file",
     cl::desc("A file containing regexes of symbol names that are not expected "
@@ -135,7 +151,7 @@ int main(int argc, const char **argv) {
   SourceManager Sources(Diagnostics, FileMgr);
   Rewriter Rewrite(Sources, DefaultLangOptions);
 
-  if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+  if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style, StyleSearchPaths)) {
     llvm::errs() << "Failed applying all replacements.\n";
     return 1;
   }
diff --git a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
index 3a11a22def1946..febbd4021ac4b7 100644
--- a/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
+++ b/clang-tools-extra/clang-include-fixer/tool/ClangIncludeFixer.cpp
@@ -157,6 +157,24 @@ cl::opt<std::string>
                    "headers if there is no clang-format config file found."),
           cl::init("llvm"), cl::cat(IncludeFixerCategory));
 
+static cl::list<std::string>
+StyleSearchPaths(
+    "style-search-path",
+    cl::desc("Directory to search for BasedOnStyle files, when the value of the\n"
+             "BasedOnStyle directive is not one of the predefined styles, nor\n"
+             "InheritFromParent. Multiple style search paths may be specified,\n"
+             "and will be searched in order, stopping at the first file found."),
+    cl::value_desc("directory"),
+    cl::cat(IncludeFixerCategory));
+
+static cl::alias
+StyleSearchPathShort(
+    "S",
+    cl::desc("Alias for --style-search-path"),
+    cl::cat(IncludeFixerCategory),
+    cl::aliasopt(StyleSearchPaths),
+    cl::NotHidden );
+
 std::unique_ptr<include_fixer::SymbolIndexManager>
 createSymbolIndexManager(StringRef FilePath) {
   using find_all_symbols::SymbolInfo;
@@ -330,7 +348,7 @@ int includeFixerMain(int argc, const char **argv) {
           return LHS.QualifiedName == RHS.QualifiedName;
         });
     auto InsertStyle = format::getStyle(format::DefaultFormatStyle,
-                                        Context.getFilePath(), Style);
+                                        Context.getFilePath(), StyleSearchPaths, Style);
     if (!InsertStyle) {
       llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
       return 1;
@@ -410,7 +428,7 @@ int includeFixerMain(int argc, const char **argv) {
   for (const auto &Context : Contexts) {
     StringRef FilePath = Context.getFilePath();
     auto InsertStyle =
-        format::getStyle(format::DefaultFormatStyle, FilePath, Style);
+        format::getStyle(format::DefaultFormatStyle, FilePath, StyleSearchPaths, Style);
     if (!InsertStyle) {
       llvm::errs() << llvm::toString(InsertStyle.takeError()) << "\n";
       return 1;
diff --git a/clang-tools-extra/clang-move/Move.cpp b/clang-tools-extra/clang-move/Move.cpp
index ac16803b46783e..d5068d3087b44f 100644
--- a/clang-tools-extra/clang-move/Move.cpp
+++ b/clang-tools-extra/clang-move/Move.cpp
@@ -781,6 +781,7 @@ void ClangMoveTool::removeDeclsInOldFiles() {
     if (SI == FilePathToFileID.end()) continue;
     llvm::StringRef Code = SM.getBufferData(SI->second);
     auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
+                                  Context->StyleSearchPaths,
                                   Context->FallbackStyle);
     if (!Style) {
       llvm::errs() << llvm::toString(Style.takeError()) << "\n";
diff --git a/clang-tools-extra/clang-move/Move.h b/clang-tools-extra/clang-move/Move.h
index ea241bbbc4f8a0..a368fac3645dbf 100644
--- a/clang-tools-extra/clang-move/Move.h
+++ b/clang-tools-extra/clang-move/Move.h
@@ -89,6 +89,9 @@ struct ClangMoveContext {
   // directory when analyzing the source file. We save the original working
   // directory in order to get the absolute file path for the fields in Spec.
   std::string OriginalRunningDirectory;
+  // Specifies the list of paths to be searched when BasedOnStyle
+  // in a .clang-format file specifies an arbitrary file to include
+  std::vector<std::string> StyleSearchPaths;
   // The name of a predefined code style.
   std::string FallbackStyle;
   // Whether dump all declarations in old header.
diff --git a/clang-tools-extra/clang-move/tool/ClangMove.cpp b/clang-tools-extra/clang-move/tool/ClangMove.cpp
index 1560dcaad67793..5ea3ef218ed0f3 100644
--- a/clang-tools-extra/clang-move/tool/ClangMove.cpp
+++ b/clang-tools-extra/clang-move/tool/ClangMove.cpp
@@ -76,6 +76,22 @@ cl::opt<bool>
                             "add #include of old header to new header."),
                    cl::init(false), cl::cat(ClangMoveCategory));
 
+cl::list<std::string>
+    StyleSearchPaths("style-search-path",
+                     cl::desc("Directory to search for BasedOnStyle files, when the value of the\n"
+                              "BasedOnStyle directive is not one of the predefined styles, nor\n"
+                              "InheritFromParent. Multiple style search paths may be specified,\n"
+                              "and will be searched in order, stopping at the first file found."),
+                     cl::value_desc("directory"),
+                     cl::cat(ClangMoveCategory));
+
+cl::alias
+    StyleSearchPathShort("S",
+                         cl::desc("Alias for --style-search-path"),
+                         cl::cat(ClangMoveCategory),
+                         cl::aliasopt(StyleSearchPaths),
+                         cl::NotHidden);
+
 cl::opt<std::string>
     Style("style",
           cl::desc("The style name used for reformatting. Default is \"llvm\""),
@@ -131,8 +147,8 @@ int main(int argc, const char **argv) {
                              Twine(EC.message()));
 
   move::ClangMoveContext Context{Spec, Tool.getReplacements(),
-                                 std::string(InitialDirectory), Style,
-                                 DumpDecls};
+                                 std::string(InitialDirectory), StyleSearchPaths,
+                                 Style, DumpDecls};
   move::DeclarationReporter Reporter;
   move::ClangMoveActionFactory Factory(&Context, &Reporter);
 
@@ -185,7 +201,7 @@ int main(int argc, const char **argv) {
   SourceManager SM(Diagnostics, FileMgr);
   Rewriter Rewrite(SM, LangOptions());
 
-  if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+  if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style, StyleSearchPaths)) {
     llvm::errs() << "Failed applying all replacements.\n";
     return 1;
   }
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index 1cd7cdd10bc25f..32b0de29291ce4 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -209,7 +209,8 @@ class ErrorReporter {
         }
         StringRef Code = Buffer.get()->getBuffer();
         auto Style = format::getStyle(
-            *Context.getOptionsForFile(File).FormatStyle, File, "none");
+            *Context.getOptionsForFile(File).FormatStyle, File,
+            Context.getGlobalOptions().StyleSearchPaths, "none");
         if (!Style) {
           llvm::errs() << llvm::toString(Style.takeError()) << "\n";
           continue;
diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
index 85d5a02ebbc1bc..e71299c3278361 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h
@@ -42,6 +42,10 @@ struct ClangTidyGlobalOptions {
   /// Output warnings from certain line ranges of certain files only.
   /// If empty, no warnings will be filtered.
   std::vector<FileFilter> LineFilter;
+
+  /// Specifies the list of paths to be searched when BasedOnStyle
+  /// in a .clang-format file specifies an arbitrary file to include
+  std::vector<std::string> StyleSearchPaths;
 };
 
 /// Contains options for clang-tidy. These options may be read from
diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp
index 5e7a0e65690b7a..7d76b13f0735f4 100644
--- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.cpp
@@ -60,7 +60,8 @@ IncludeCleanerCheck::IncludeCleanerCheck(StringRef Name,
       IgnoreHeaders(utils::options::parseStringList(
           Options.getLocalOrGlobal("IgnoreHeaders", ""))),
       DeduplicateFindings(
-          Options.getLocalOrGlobal("DeduplicateFindings", true)) {
+          Options.getLocalOrGlobal("DeduplicateFindings", true)),
+      StyleSearchPaths(Context->getGlobalOptions().StyleSearchPaths) {
   for (const auto &Header : IgnoreHeaders) {
     if (!llvm::Regex{Header}.isValid())
       configurationDiag("Invalid ignore headers regex '%0'") << Header;
@@ -196,7 +197,7 @@ void IncludeCleanerCheck::check(const MatchFinder::MatchResult &Result) {
   llvm::StringRef Code = SM->getBufferData(SM->getMainFileID());
   auto FileStyle =
       format::getStyle(format::DefaultFormatStyle, getCurrentMainFile(),
-                       format::DefaultFallbackStyle, Code,
+                       StyleSearchPaths, format::DefaultFallbackStyle, Code,
                        &SM->getFileManager().getVirtualFileSystem());
   if (!FileStyle)
     FileStyle = format::getLLVMStyle();
diff --git a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h
index b46e409bd6f6a0..229c8b7127cbc9 100644
--- a/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h
+++ b/clang-tools-extra/clang-tidy/misc/IncludeCleanerCheck.h
@@ -47,6 +47,7 @@ class IncludeCleanerCheck : public ClangTidyCheck {
   std::vector<StringRef> IgnoreHeaders;
   // Whether emit only one finding per usage of a symbol.
   const bool DeduplicateFindings;
+  std::vector<std::string> StyleSearchPaths;
   llvm::SmallVector<llvm::Regex> IgnoreHeadersRegex;
   bool shouldIgnore(const include_cleaner::Header &H);
 };
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index d42dafa8ffc362..4148c3a8d9d514 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -208,6 +208,20 @@ This option overrides the 'FormatStyle` option in
                                         cl::init("none"),
                                         cl::cat(ClangTidyCategory));
 
+static cl::list<std::string> StyleSearchPaths("style-search-path", desc(R"(
+Directory to search for BasedOnStyle files, when the value of the
+BasedOnStyle directive is not one of the predefined styles, nor
+InheritFromParent. Multiple style search paths may be specified,
+and will be searched in order, stopping at the first file found.
+)"),
+                                              cl::value_desc("directory"),
+                                              cl::cat(ClangTidyCategory));
+
+static cl::alias StyleSearchPathShort("S", cl::desc("Alias for --style-search-path"),
+                                      cl::cat(ClangTidyCategory),
+                                      cl::aliasopt(StyleSearchPaths),
+                                      cl::NotHidden);
+
 static cl::opt<bool> ListChecks("list-checks", desc(R"(
 List all enabled checks and exit. Use with
 -checks=* to list all available checks.
@@ -366,6 +380,7 @@ static void printStats(const ClangTidyStats &Stats) {
 static std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider(
    llvm::IntrusiveRefCntPtr<vfs::FileSystem> FS) {
   ClangTidyGlobalOptions GlobalOptions;
+  GlobalOptions.StyleSearchPaths = StyleSearchPaths;
   if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
     llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
     llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 06573a57554245..a169a7885c0679 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -1650,7 +1650,7 @@ ClangdLSPServer::ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,
     assert(!Opts.ContextProvider &&
            "Only one of ConfigProvider and ContextProvider allowed!");
     this->Opts.ContextProvider = ClangdServer::createConfiguredContextProvider(
-        Opts.ConfigProvider, this);
+        Opts.ConfigProvider, this, Opts.StyleSearchPaths);
   }
   LSPBinder Bind(this->Handlers, *this);
   Bind.method("initialize", this, &ClangdLSPServer::onInitialize);
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index e910a80ba0bae9..cfd60bb8279077 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -223,6 +223,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
       PreambleParseForwardingFunctions(Opts.PreambleParseForwardingFunctions),
       ImportInsertions(Opts.ImportInsertions),
       PublishInactiveRegions(Opts.PublishInactiveRegions),
+      StyleSearchPaths(Opts.StyleSearchPaths),
       WorkspaceRoot(Opts.WorkspaceRoot),
       Transient(Opts.ImplicitCancellation ? TUScheduler::InvalidateOnUpdate
                                           : TUScheduler::NoInvalidation),
@@ -335,17 +336,20 @@ std::shared_ptr<const std::string> ClangdServer::getDraft(PathRef File) const {
 
 std::function<Context(PathRef)>
 ClangdServer::createConfiguredContextProvider(const config::Provider *Provider,
-                                              Callbacks *Publish) {
+                                              Callbacks *Publish,
+                                              const std::vector<std::string> &StyleSearchPaths) {
   if (!Provider)
     return [](llvm::StringRef) { return Context::current().clone(); };
 
   struct Impl {
     const config::Provider *Provider;
     ClangdServer::Callbacks *Publish;
+    std::vector<std::string> StyleSearchPaths;
     std::mutex PublishMu;
 
-    Impl(const config::Provider *Provider, ClangdServer::Callbacks *Publish)
-        : Provider(Provider), Publish(Publish) {}
+    Impl(const config::Provider *Provider, ClangdServer::Callbacks *Publish,
+         const std::vector<std::string> &StyleSearchPaths)
+        : Provider(Provider), Publish(Publish), StyleSearchPaths(StyleSearchPaths) {}
 
     Context operator()(llvm::StringRef File) {
       config::Params Params;
@@ -378,6 +382,7 @@ ClangdServer::createConfiguredContextProvider(const config::Provider *Provider,
           Publish->onDiagnosticsReady(Entry.first(), /*Version=*/"",
                                       Entry.second);
       }
+      C.Style.StyleSearchPaths = StyleSearchPaths;
       return Context::current().derive(Config::Key, std::move(C));
     }
 
@@ -405,7 +410,7 @@ ClangdServer::createConfiguredContextProvider(const config::Provider *Provider,
   };
 
   // Copyable wrapper.
-  return [I(std::make_shared<Impl>(Provider, Publish))](llvm::StringRef Path) {
+  return [I(std::make_shared<Impl>(Provider, Publish, StyleSearchPaths))](llvm::StringRef Path) {
     return (*I)(Path);
   };
 }
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index a653cdb56b751b..58d5bd6f013494 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -96,7 +96,8 @@ class ClangdServer {
   /// (This is typically used as ClangdServer::Options::ContextProvider).
   static std::function<Context(PathRef)>
   createConfiguredContextProvider(const config::Provider *Provider,
-                                  ClangdServer::Callbacks *);
+                                  ClangdServer::Callbacks *,
+                                  const std::vector<std::string> &StyleSearchPaths);
 
   struct Options {
     /// To process requests asynchronously, ClangdServer spawns worker threads.
@@ -142,6 +143,10 @@ class ClangdServer {
     /// checks will be disabled.
     TidyProviderRef ClangTidyProvider;
 
+    /// Specifies the list of paths to be searched when BasedOnStyle
+    /// in a .clang-format file specifies an arbitrary file to include
+    std::vector<std::string> StyleSearchPaths;
+
     /// Clangd's workspace root. Relevant for "workspace" operations not bound
     /// to a particular file.
     /// FIXME: If not set, should use the current working directory.
@@ -487,6 +492,10 @@ class ClangdServer {
   // When set, provides clang-tidy options for a specific file.
   TidyProviderRef ClangTidyProvider;
 
+  // Specifies the list of paths to be searched when BasedOnStyle
+  // in a .clang-format file specifies an arbitrary file to include
+  std::vector<std::string> StyleSearchPaths;
+
   bool UseDirtyHeaders = false;
 
   // Whether the client supports folding only complete lines.
diff --git a/clang-tools-extra/clangd/Config.h b/clang-tools-extra/clangd/Config.h
index 41143b9ebc8d27..3bb3775bf7e4fa 100644
--- a/clang-tools-extra/clangd/Config.h
+++ b/clang-tools-extra/clangd/Config.h
@@ -124,6 +124,10 @@ struct Config {
     // declarations, always spell out the whole name (with or without leading
     // ::). All nested namespaces are affected as well.
     std::vector<std::string> FullyQualifiedNamespaces;
+
+    // Specifies the list of paths to be searched when BasedOnStyle
+    // in a .clang-format file specifies an arbitrary file to include
+    std::vector<std::string> StyleSearchPaths;
   } Style;
 
   /// Configures code completion feature.
diff --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp
index e34706172f0bf6..130b923bbd5efc 100644
--- a/clang-tools-extra/clangd/IncludeCleaner.cpp
+++ b/clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "IncludeCleaner.h"
+#include "Config.h"
 #include "Diagnostics.h"
 #include "Headers.h"
 #include "ParsedAST.h"
diff --git a/clang-tools-extra/clangd/SourceCode.cpp b/clang-tools-extra/clangd/SourceCode.cpp
index 3af99b9db056da..3f08159fc6ffd2 100644
--- a/clang-tools-extra/clangd/SourceCode.cpp
+++ b/clang-tools-extra/clangd/SourceCode.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 #include "SourceCode.h"
 
+#include "Config.h"
 #include "FuzzyMatch.h"
 #include "Preamble.h"
 #include "Protocol.h"
@@ -597,7 +598,9 @@ format::FormatStyle getFormatStyleForFile(llvm::StringRef File,
   // language is detected.
   if (!FormatFile)
     Content = {};
+  auto &Cfg = Config::current();
   auto Style = format::getStyle(format::DefaultFormatStyle, File,
+                                Cfg.Style.StyleSearchPaths,
                                 format::DefaultFallbackStyle, Content,
                                 TFS.view(/*CWD=*/std::nullopt).get());
   if (!Style) {
diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp
index bc2eaa77a66eec..9a9b4be967087a 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -512,7 +512,7 @@ bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
       config::Provider::combine({Opts.ConfigProvider, &OverrideConfig});
 
   auto ContextProvider = ClangdServer::createConfiguredContextProvider(
-      ConfigProvider.get(), nullptr);
+      ConfigProvider.get(), nullptr, Opts.StyleSearchPaths);
   WithContext Ctx(ContextProvider(
       FakeFile.empty()
           ? File
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 3a5449ac8c7994..e27e9ef0e4fcec 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -69,16 +69,20 @@ bool check(const llvm::StringRef File, const ThreadsafeFS &TFS,
 
 namespace {
 
+using llvm::cl::alias;
+using llvm::cl::aliasopt;
 using llvm::cl::cat;
 using llvm::cl::CommaSeparated;
 using llvm::cl::desc;
 using llvm::cl::Hidden;
 using llvm::cl::init;
 using llvm::cl::list;
+using llvm::cl::NotHidden;
 using llvm::cl::opt;
 using llvm::cl::OptionCategory;
 using llvm::cl::ValueOptional;
 using llvm::cl::values;
+using llvm::cl::value_desc;
 
 // All flags must be placed in a category, or they will be shown neither in
 // --help, nor --help-hidden!
@@ -242,6 +246,24 @@ opt<std::string> FallbackStyle{
     init(clang::format::DefaultFallbackStyle),
 };
 
+list<std::string> StyleSearchPaths{
+    "style-search-path",
+    desc("Directory to search for BasedOnStyle files, when the value of the "
+         "BasedOnStyle directive is not one of the predefined styles, nor "
+         "InheritFromParent. Multiple style search paths may be specified, "
+         "and will be searched in order, stopping at the first file found."),
+    value_desc("directory"),
+    cat(Features)
+};
+
+alias StyleSearchPathShort{
+    "S",
+    desc("Alias for --style-search-path"),
+    cat(Features),
+    aliasopt(StyleSearchPaths),
+    NotHidden
+};
+
 opt<bool> EnableFunctionArgSnippets{
     "function-arg-placeholders",
     cat(Features),
@@ -957,6 +979,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
     ClangTidyOptProvider = combine(std::move(Providers));
     Opts.ClangTidyProvider = ClangTidyOptProvider;
   }
+  Opts.StyleSearchPaths = StyleSearchPaths;
   Opts.UseDirtyHeaders = UseDirtyHeaders;
   Opts.PreambleParseForwardingFunctions = PreambleParseForwardingFunctions;
   Opts.ImportInsertions = ImportInsertions;
diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
index c324643498d94c..2ea9f06495720b 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -348,7 +348,7 @@ TEST(ClangdServerTest, RespectsConfig) {
 
   auto Opts = ClangdServer::optsForTest();
   Opts.ContextProvider =
-      ClangdServer::createConfiguredContextProvider(&CfgProvider, nullptr);
+      ClangdServer::createConfiguredContextProvider(&CfgProvider, nullptr, Opts.StyleSearchPaths);
   OverlayCDB CDB(/*Base=*/nullptr, /*FallbackFlags=*/{},
                  CommandMangler::forTests());
   MockFS FS;
diff --git a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
index d8a44ab9b6e12e..1b141835402293 100644
--- a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
+++ b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
@@ -104,10 +104,23 @@ cl::opt<bool> Remove{
     cl::cat(IncludeCleaner),
 };
 
+static cl::list<std::string> StyleSearchPaths("style-search-path", cl::desc(R"(
+Directory to search for BasedOnStyle files, when the value of the
+BasedOnStyle directive is not one of the predefined styles, nor
+InheritFromParent. Multiple style search paths may be specified,
+and will be searched in order, stopping at the first file found.
+)"),
+                                              cl::value_desc("directory"),
+                                              cl::cat(IncludeCleaner));
+
+static cl::alias StyleSearchPathShort("S", cl::desc("Alias for --style-search-path"),
+                                      cl::cat(IncludeCleaner), cl::aliasopt(StyleSearchPaths),
+                                      cl::NotHidden);
+
 std::atomic<unsigned> Errors = ATOMIC_VAR_INIT(0);
 
 format::FormatStyle getStyle(llvm::StringRef Filename) {
-  auto S = format::getStyle(format::DefaultFormatStyle, Filename,
+  auto S = format::getStyle(format::DefaultFormatStyle, Filename, StyleSearchPaths,
                             format::DefaultFallbackStyle);
   if (!S || !S->isCpp()) {
     consumeError(S.takeError());
diff --git a/clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp b/clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
index 4a6352cd5975e6..08db97a4e90734 100644
--- a/clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
+++ b/clang-tools-extra/unittests/clang-change-namespace/ChangeNamespaceTests.cpp
@@ -46,7 +46,7 @@ class ChangeNamespaceTest : public ::testing::Test {
     if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, {"-std=c++11"},
                                         FileName))
       return "";
-    formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite);
+    formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "file", {} /*StyleSearchPatsh*/);
     return format(Context.getRewrittenText(ID));
   }
 
diff --git a/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp b/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp
index 082779358fbfb1..06ec26bc237fba 100644
--- a/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp
+++ b/clang-tools-extra/unittests/clang-move/ClangMoveTests.cpp
@@ -226,7 +226,7 @@ runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
   CreateFiles(TestCCName, CC);
 
   std::map<std::string, tooling::Replacements> FileToReplacements;
-  ClangMoveContext MoveContext = {Spec, FileToReplacements, Dir.c_str(), "LLVM",
+  ClangMoveContext MoveContext = {Spec, FileToReplacements, Dir.c_str(), /*StyleSearchPaths*/{}, "LLVM",
                                   Reporter != nullptr};
 
   auto Factory = std::make_unique<clang::move::ClangMoveActionFactory>(
@@ -236,7 +236,7 @@ runClangMoveOnCode(const move::MoveDefinitionSpec &Spec,
       Factory->create(), CC, Context.InMemoryFileSystem,
       {"-std=c++11", "-fparse-all-comments", "-I."}, TestCCName, "clang-move",
       std::make_shared<PCHContainerOperations>());
-  formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
+  formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm", /*StyleSearchPaths*/{});
   // The Key is file name, value is the new code after moving the class.
   std::map<std::string, std::string> Results;
   for (const auto &It : FileToReplacements) {
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index d8b62c7652a0f6..79b0313bb6b3c0 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -5274,9 +5274,17 @@ struct FormatStyle {
 
   friend std::error_code
   parseConfiguration(llvm::MemoryBufferRef Config, FormatStyle *Style,
+                     const std::vector<std::string> &StyleSearchPaths,
                      bool AllowUnknownOptions,
                      llvm::SourceMgr::DiagHandlerTy DiagHandler,
                      void *DiagHandlerCtxt);
+
+  friend std::error_code
+  parseNestedConfiguration(llvm::MemoryBufferRef Config, FormatStyle *Style,
+                           const std::vector<std::string> &StyleSearchPaths,
+                           bool AllowUnknownOptions,
+                           llvm::SourceMgr::DiagHandlerTy DiagHandler,
+                           void *DiagHandlerCtxt);
 };
 
 /// Returns a format style complying with the LLVM coding standards:
@@ -5340,17 +5348,30 @@ bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language,
 /// If set all diagnostics are emitted through the DiagHandler.
 std::error_code
 parseConfiguration(llvm::MemoryBufferRef Config, FormatStyle *Style,
+                   const std::vector<std::string> &StyleSearchPaths,
                    bool AllowUnknownOptions = false,
                    llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr,
                    void *DiagHandlerCtx = nullptr);
 
 /// Like above but accepts an unnamed buffer.
 inline std::error_code parseConfiguration(StringRef Config, FormatStyle *Style,
+                                          const std::vector<std::string> &StyleSearchPaths,
                                           bool AllowUnknownOptions = false) {
   return parseConfiguration(llvm::MemoryBufferRef(Config, "YAML"), Style,
-                            AllowUnknownOptions);
+                            StyleSearchPaths, AllowUnknownOptions);
 }
 
+/// Like above but discards Style->StyleSet after resolving the desired style.
+/// This allows a BasedOnStyle that references a YAML file included via StyleSearchPaths
+/// (which might contain styles for multiple langages) to be consumed while maintaining
+/// the invariant that a FormatStyle may belong to only one StyleSet.
+std::error_code
+parseNestedConfiguration(llvm::MemoryBufferRef Config, FormatStyle *Style,
+                         const std::vector<std::string> &StyleSearchPaths,
+                         bool AllowUnknownOptions,
+                         llvm::SourceMgr::DiagHandlerTy DiagHandler,
+                         void *DiagHandlerCtxt);
+
 /// Gets configuration in a YAML string.
 std::string configurationAsText(const FormatStyle &Style);
 
@@ -5493,6 +5514,8 @@ extern const char *DefaultFallbackStyle;
 /// above.
 /// \param[in] FileName Path to start search for .clang-format if ``StyleName``
 /// == "file".
+/// \param[in] StyleSearchPaths The sequence of directories to be searched when
+/// resolving a non-built-in BasedOnStyle to a filesystem path.
 /// \param[in] FallbackStyle The name of a predefined style used to fallback to
 /// in case \p StyleName is "file" and no file can be found.
 /// \param[in] Code The actual code to be formatted. Used to determine the
@@ -5507,7 +5530,9 @@ extern const char *DefaultFallbackStyle;
 /// "file" and no file is found, returns ``FallbackStyle``. If no style could be
 /// determined, returns an Error.
 Expected<FormatStyle>
-getStyle(StringRef StyleName, StringRef FileName, StringRef FallbackStyle,
+getStyle(StringRef StyleName, StringRef FileName,
+         const std::vector<std::string> &StyleSearchPaths,
+         StringRef FallbackStyle,
          StringRef Code = "", llvm::vfs::FileSystem *FS = nullptr,
          bool AllowUnknownOptions = false,
          llvm::SourceMgr::DiagHandlerTy DiagHandler = nullptr);
diff --git a/clang/include/clang/Tooling/Refactoring.h b/clang/include/clang/Tooling/Refactoring.h
index b82b09f0f92dbd..f505300f4d4640 100644
--- a/clang/include/clang/Tooling/Refactoring.h
+++ b/clang/include/clang/Tooling/Refactoring.h
@@ -87,11 +87,13 @@ class RefactoringTool : public ClangTool {
 /// \param[in] Rewrite The `Rewritter` to apply replacements on.
 /// \param[in] Style The style name used for reformatting. See ```getStyle``` in
 /// "include/clang/Format/Format.h" for all possible style forms.
+/// \param[in] StyleSearchPaths A list of directories to search for clang-format
+/// files referenced in the BasedOnStyle directive.
 ///
 /// \returns true if all replacements applied and formatted. false otherwise.
 bool formatAndApplyAllReplacements(
     const std::map<std::string, Replacements> &FileToReplaces,
-    Rewriter &Rewrite, StringRef Style = "file");
+    Rewriter &Rewrite, StringRef Style, const std::vector<std::string>& StyleSearchPaths);
 
 } // end namespace tooling
 } // end namespace clang
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index d2463b892fbb96..d6bc46ffab66bc 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -853,8 +853,21 @@ template <> struct MappingTraits<FormatStyle> {
         FormatStyle::LanguageKind Language =
             ((FormatStyle *)IO.getContext())->Language;
         if (!getPredefinedStyle(BasedOnStyle, Language, &Style)) {
-          IO.setError(Twine("Unknown value for BasedOnStyle: ", BasedOnStyle));
-          return;
+          // OK, not a predefined style. See if this is an includable file.
+          SourceMgr& SrcMgr = IO.getSourceMgr();
+          std::string IncludedFile;
+          ErrorOr<std::unique_ptr<MemoryBuffer>> IncFileOrError = SrcMgr.OpenIncludeFile(BasedOnStyle.str(), IncludedFile);
+          if (!IncFileOrError) {
+            IO.setError(Twine("BasedOnStyle value is not a predefined style nor a file relative to the style search path: ", BasedOnStyle));
+            return;
+          }
+          Style.Language = Language;
+          if (auto EC = parseNestedConfiguration((*IncFileOrError)->getMemBufferRef(), &Style,
+                                                 SrcMgr.getIncludeDirs(), IO.allowUnknownKeys(),
+                                                 SrcMgr.getDiagHandler(), SrcMgr.getDiagContext())) {
+            IO.setError(Twine(EC.message()));
+            return;
+          }
         }
         Style.Language = OldLanguage;
       }
@@ -2033,7 +2046,9 @@ ParseError validateQualifierOrder(FormatStyle *Style) {
 }
 
 std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
-                                   FormatStyle *Style, bool AllowUnknownOptions,
+                                   FormatStyle *Style,
+                                   const std::vector<std::string> &StyleSearchPaths,
+                                   bool AllowUnknownOptions,
                                    llvm::SourceMgr::DiagHandlerTy DiagHandler,
                                    void *DiagHandlerCtxt) {
   assert(Style);
@@ -2051,6 +2066,7 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
   // base style.
   Input.setContext(Style);
   Input.setAllowUnknownKeys(AllowUnknownOptions);
+  Input.getSourceMgr().setIncludeDirs(StyleSearchPaths);
   Input >> Styles;
   if (Input.error())
     return Input.error();
@@ -2098,6 +2114,18 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
   return make_error_code(ParseError::Success);
 }
 
+std::error_code parseNestedConfiguration(llvm::MemoryBufferRef Config,
+                                         FormatStyle *Style,
+                                         const std::vector<std::string> &StyleSearchPaths,
+                                         bool AllowUnknownOptions,
+                                         llvm::SourceMgr::DiagHandlerTy DiagHandler,
+                                         void *DiagHandlerCtxt) {
+  auto EC = parseConfiguration(Config, Style, StyleSearchPaths, AllowUnknownOptions, DiagHandler, DiagHandlerCtxt);
+  if (!EC)
+    Style->StyleSet.Clear();
+  return EC;
+}
+
 std::string configurationAsText(const FormatStyle &Style) {
   std::string Text;
   llvm::raw_string_ostream Stream(Text);
@@ -3991,13 +4019,15 @@ const char *DefaultFallbackStyle = "LLVM";
 
 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
 loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS,
-                       FormatStyle *Style, bool AllowUnknownOptions,
+                       FormatStyle *Style,
+                       const std::vector<std::string> &StyleSearchPaths,
+                       bool AllowUnknownOptions,
                        llvm::SourceMgr::DiagHandlerTy DiagHandler) {
   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
       FS->getBufferForFile(ConfigFile.str());
   if (auto EC = Text.getError())
     return EC;
-  if (auto EC = parseConfiguration(*Text.get(), Style, AllowUnknownOptions,
+  if (auto EC = parseConfiguration(*Text.get(), Style, StyleSearchPaths, AllowUnknownOptions,
                                    DiagHandler)) {
     return EC;
   }
@@ -4005,6 +4035,7 @@ loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS,
 }
 
 Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
+                               const std::vector<std::string> &StyleSearchPaths,
                                StringRef FallbackStyleName, StringRef Code,
                                llvm::vfs::FileSystem *FS,
                                bool AllowUnknownOptions,
@@ -4021,7 +4052,7 @@ Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
     StringRef Source = "<command-line>";
     if (std::error_code ec =
             parseConfiguration(llvm::MemoryBufferRef(StyleName, Source), &Style,
-                               AllowUnknownOptions, DiagHandler)) {
+                               StyleSearchPaths, AllowUnknownOptions, DiagHandler)) {
       return make_string_error("Error parsing -style: " + ec.message());
     }
 
@@ -4041,8 +4072,8 @@ Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
       StyleName.starts_with_insensitive("file:")) {
     auto ConfigFile = StyleName.substr(5);
     llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
-        loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions,
-                               DiagHandler);
+        loadAndParseConfigFile(ConfigFile, FS, &Style, StyleSearchPaths,
+                               AllowUnknownOptions, DiagHandler);
     if (auto EC = Text.getError()) {
       return make_string_error("Error reading " + ConfigFile + ": " +
                                EC.message());
@@ -4082,7 +4113,7 @@ Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
   auto applyChildFormatTexts = [&](FormatStyle *Style) {
     for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) {
       auto EC =
-          parseConfiguration(*MemBuf, Style, AllowUnknownOptions,
+          parseConfiguration(*MemBuf, Style, StyleSearchPaths, AllowUnknownOptions,
                              DiagHandler ? DiagHandler : dropDiagnosticHandler);
       // It was already correctly parsed.
       assert(!EC);
@@ -4117,7 +4148,7 @@ Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
       }
 
       llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
-          loadAndParseConfigFile(ConfigFile, FS, &Style, AllowUnknownOptions,
+          loadAndParseConfigFile(ConfigFile, FS, &Style, StyleSearchPaths, AllowUnknownOptions,
                                  DiagHandler);
       if (auto EC = Text.getError()) {
         if (EC != ParseError::Unsuitable) {
diff --git a/clang/lib/Tooling/Refactoring.cpp b/clang/lib/Tooling/Refactoring.cpp
index 961fc1c1801547..8221957648f88a 100644
--- a/clang/lib/Tooling/Refactoring.cpp
+++ b/clang/lib/Tooling/Refactoring.cpp
@@ -68,7 +68,7 @@ int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
 
 bool formatAndApplyAllReplacements(
     const std::map<std::string, Replacements> &FileToReplaces,
-    Rewriter &Rewrite, StringRef Style) {
+    Rewriter &Rewrite, StringRef Style, const std::vector<std::string>& StyleSearchPaths) {
   SourceManager &SM = Rewrite.getSourceMgr();
   FileManager &Files = SM.getFileManager();
 
@@ -82,7 +82,7 @@ bool formatAndApplyAllReplacements(
     FileID ID = SM.getOrCreateFileID(Entry, SrcMgr::C_User);
     StringRef Code = SM.getBufferData(ID);
 
-    auto CurStyle = format::getStyle(Style, FilePath, "LLVM");
+    auto CurStyle = format::getStyle(Style, FilePath, StyleSearchPaths, "LLVM");
     if (!CurStyle) {
       llvm::errs() << llvm::toString(CurStyle.takeError()) << "\n";
       return false;
diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp
index 6aed46328f3469..0cca1e1c4c4d15 100644
--- a/clang/tools/clang-format/ClangFormat.cpp
+++ b/clang/tools/clang-format/ClangFormat.cpp
@@ -172,6 +172,24 @@ static cl::opt<bool>
                      cl::desc("If set, changes formatting warnings to errors"),
                      cl::cat(ClangFormatCategory));
 
+static cl::list<std::string>
+    StyleSearchPaths(
+    "style-search-path",
+    cl::desc("Directory to search for BasedOnStyle files, when the value of the\n"
+             "BasedOnStyle directive is not one of the predefined styles, nor\n"
+             "InheritFromParent. Multiple style search paths may be specified,\n"
+             "and will be searched in order, stopping at the first file found."),
+    cl::value_desc("directory"),
+    cl::cat(ClangFormatCategory));
+
+static cl::alias
+    StyleSearchPathShort(
+    "S",
+    cl::desc("Alias for --style-search-path"),
+    cl::cat(ClangFormatCategory),
+    cl::aliasopt(StyleSearchPaths),
+    cl::NotHidden);
+
 namespace {
 enum class WNoError { Unknown };
 }
@@ -452,7 +470,7 @@ static bool format(StringRef FileName, bool ErrorOnIncompleteFormat = false) {
   }
 
   Expected<FormatStyle> FormatStyle =
-      getStyle(Style, AssumedFileName, FallbackStyle, Code->getBuffer(),
+      getStyle(Style, AssumedFileName, StyleSearchPaths, FallbackStyle, Code->getBuffer(),
                nullptr, WNoErrorList.isSet(WNoError::Unknown));
   if (!FormatStyle) {
     llvm::errs() << toString(FormatStyle.takeError()) << "\n";
@@ -573,6 +591,7 @@ static int dumpConfig() {
   Expected<clang::format::FormatStyle> FormatStyle = clang::format::getStyle(
       Style,
       FileNames.empty() || FileNames[0] == "-" ? AssumeFileName : FileNames[0],
+      StyleSearchPaths,
       FallbackStyle, Code ? Code->getBuffer() : "");
   if (!FormatStyle) {
     llvm::errs() << toString(FormatStyle.takeError()) << "\n";
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index b8bdfaaa74e10e..31b99b640fb5b0 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -80,27 +80,27 @@ TEST(ConfigParseTest, GetsCorrectBasedOnStyle) {
 
   Styles[0] = getGoogleStyle();
   Styles[1] = getLLVMStyle();
-  EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Styles[1]).value());
+  EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Styles[1], /*StyleSearchPaths*/{}).value());
   EXPECT_ALL_STYLES_EQUAL(Styles);
 
   Styles.resize(5);
   Styles[0] = getGoogleStyle(FormatStyle::LK_JavaScript);
   Styles[1] = getLLVMStyle();
   Styles[1].Language = FormatStyle::LK_JavaScript;
-  EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Styles[1]).value());
+  EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Styles[1], /*StyleSearchPaths*/{}).value());
 
   Styles[2] = getLLVMStyle();
   Styles[2].Language = FormatStyle::LK_JavaScript;
   EXPECT_EQ(0, parseConfiguration("Language: JavaScript\n"
                                   "BasedOnStyle: Google",
-                                  &Styles[2])
+                                  &Styles[2], /*StyleSearchPaths*/{})
                    .value());
 
   Styles[3] = getLLVMStyle();
   Styles[3].Language = FormatStyle::LK_JavaScript;
   EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google\n"
                                   "Language: JavaScript",
-                                  &Styles[3])
+                                  &Styles[3], /*StyleSearchPaths*/{})
                    .value());
 
   Styles[4] = getLLVMStyle();
@@ -111,16 +111,18 @@ TEST(ConfigParseTest, GetsCorrectBasedOnStyle) {
                                   "---\n"
                                   "BasedOnStyle: Google\n"
                                   "Language: JavaScript",
-                                  &Styles[4])
+                                  &Styles[4], /*StyleSearchPaths*/{})
                    .value());
   EXPECT_ALL_STYLES_EQUAL(Styles);
 }
 
 #define CHECK_PARSE_BOOL_FIELD(FIELD, CONFIG_NAME)                             \
   Style.FIELD = false;                                                         \
-  EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": true", &Style).value());      \
+  EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": true", &Style,                \
+                                  /*StyleSearchPaths*/{}).value());            \
   EXPECT_TRUE(Style.FIELD);                                                    \
-  EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": false", &Style).value());     \
+  EXPECT_EQ(0, parseConfiguration(CONFIG_NAME ": false", &Style,               \
+                                  /*StyleSearchPaths*/{}).value());            \
   EXPECT_FALSE(Style.FIELD)
 
 #define CHECK_PARSE_BOOL(FIELD) CHECK_PARSE_BOOL_FIELD(FIELD, #FIELD)
@@ -128,11 +130,13 @@ TEST(ConfigParseTest, GetsCorrectBasedOnStyle) {
 #define CHECK_PARSE_NESTED_BOOL_FIELD(STRUCT, FIELD, CONFIG_NAME)              \
   Style.STRUCT.FIELD = false;                                                  \
   EXPECT_EQ(0,                                                                 \
-            parseConfiguration(#STRUCT ":\n  " CONFIG_NAME ": true", &Style)   \
+            parseConfiguration(#STRUCT ":\n  " CONFIG_NAME ": true",           \
+                               &Style, /*StyleSearchPaths*/{})                 \
                 .value());                                                     \
   EXPECT_TRUE(Style.STRUCT.FIELD);                                             \
   EXPECT_EQ(0,                                                                 \
-            parseConfiguration(#STRUCT ":\n  " CONFIG_NAME ": false", &Style)  \
+            parseConfiguration(#STRUCT ":\n  " CONFIG_NAME ": false",          \
+                               &Style, /*StyleSearchPaths*/{})                 \
                 .value());                                                     \
   EXPECT_FALSE(Style.STRUCT.FIELD)
 
@@ -141,12 +145,13 @@ TEST(ConfigParseTest, GetsCorrectBasedOnStyle) {
 
 #define CHECK_PARSE(TEXT, FIELD, VALUE)                                        \
   EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!";          \
-  EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_EQ(0, parseConfiguration(TEXT, &Style,                                \
+                                  /*StyleSearchPaths*/{}).value());            \
   EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
-
 #define CHECK_PARSE_NESTED_VALUE(TEXT, STRUCT, FIELD, VALUE)                   \
   EXPECT_NE(VALUE, Style.STRUCT.FIELD) << "Initial value already the same!";   \
-  EXPECT_EQ(0, parseConfiguration(#STRUCT ":\n  " TEXT, &Style).value());      \
+  EXPECT_EQ(0, parseConfiguration(#STRUCT ":\n  " TEXT, &Style,                \
+                                  /*StyleSearchPaths*/{}).value());            \
   EXPECT_EQ(VALUE, Style.STRUCT.FIELD) << "Unexpected value after parsing!"
 
 TEST(ConfigParseTest, ParsesConfigurationBools) {
@@ -1065,13 +1070,13 @@ TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
               IndentWidth, 12u);
   EXPECT_EQ(parseConfiguration("Language: JavaScript\n"
                                "IndentWidth: 34",
-                               &Style),
+                               &Style, /*StyleSearchPaths*/{}),
             ParseError::Unsuitable);
   FormatStyle BinPackedTCS = {};
   BinPackedTCS.Language = FormatStyle::LK_JavaScript;
   EXPECT_EQ(parseConfiguration("BinPackArguments: true\n"
                                "InsertTrailingCommas: Wrapped",
-                               &BinPackedTCS),
+                               &BinPackedTCS, /*StyleSearchPaths*/{}),
             ParseError::BinPackTrailingCommaConflict);
   EXPECT_EQ(12u, Style.IndentWidth);
   CHECK_PARSE("IndentWidth: 56", IndentWidth, 56u);
@@ -1084,7 +1089,7 @@ TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
   CHECK_PARSE("IndentWidth: 23", IndentWidth, 23u);
   EXPECT_EQ(parseConfiguration("Language: Cpp\n"
                                "IndentWidth: 34",
-                               &Style),
+                               &Style, /*StyleSearchPaths*/{}),
             ParseError::Unsuitable);
   EXPECT_EQ(23u, Style.IndentWidth);
   CHECK_PARSE("IndentWidth: 56", IndentWidth, 56u);
@@ -1136,7 +1141,7 @@ TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
                                   "BreakBeforeBraces: Stroustrup\n"
                                   "TabWidth: 789\n"
                                   "...\n",
-                                  &Style));
+                                  &Style, /*StyleSearchPaths*/{}));
   EXPECT_EQ(123u, Style.ColumnLimit);
   EXPECT_EQ(456u, Style.IndentWidth);
   EXPECT_EQ(FormatStyle::BS_Stroustrup, Style.BreakBeforeBraces);
@@ -1148,7 +1153,7 @@ TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
                                "---\n"
                                "IndentWidth: 78\n"
                                "...\n",
-                               &Style),
+                               &Style, /*StyleSearchPaths*/{}),
             ParseError::Error);
   EXPECT_EQ(parseConfiguration("---\n"
                                "Language: JavaScript\n"
@@ -1157,7 +1162,7 @@ TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
                                "Language: JavaScript\n"
                                "IndentWidth: 78\n"
                                "...\n",
-                               &Style),
+                               &Style, /*StyleSearchPaths*/{}),
             ParseError::Error);
 
   EXPECT_EQ(FormatStyle::LK_Cpp, Style.Language);
@@ -1184,7 +1189,7 @@ TEST(ConfigParseTest, UsesLanguageForBasedOnStyle) {
   FormatStyle Style = {};
   Style.Language = FormatStyle::LK_JavaScript;
   Style.BreakBeforeTernaryOperators = true;
-  EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Style).value());
+  EXPECT_EQ(0, parseConfiguration("BasedOnStyle: Google", &Style, /*StyleSearchPaths*/{}).value());
   EXPECT_FALSE(Style.BreakBeforeTernaryOperators);
 
   Style.BreakBeforeTernaryOperators = true;
@@ -1194,7 +1199,7 @@ TEST(ConfigParseTest, UsesLanguageForBasedOnStyle) {
                                   "Language: JavaScript\n"
                                   "IndentWidth: 76\n"
                                   "...\n",
-                                  &Style)
+                                  &Style, /*StyleSearchPaths*/{})
                    .value());
   EXPECT_FALSE(Style.BreakBeforeTernaryOperators);
   EXPECT_EQ(76u, Style.IndentWidth);
@@ -1206,13 +1211,13 @@ TEST(ConfigParseTest, ConfigurationRoundTripTest) {
   std::string YAML = configurationAsText(Style);
   FormatStyle ParsedStyle = {};
   ParsedStyle.Language = FormatStyle::LK_Cpp;
-  EXPECT_EQ(0, parseConfiguration(YAML, &ParsedStyle).value());
+  EXPECT_EQ(0, parseConfiguration(YAML, &ParsedStyle, /*StyleSearchPaths*/{}).value());
   EXPECT_EQ(Style, ParsedStyle);
 }
 
 TEST(ConfigParseTest, GetStyleWithEmptyFileName) {
   llvm::vfs::InMemoryFileSystem FS;
-  auto Style1 = getStyle("file", "", "Google", "", &FS);
+  auto Style1 = getStyle("file", "", /*StyleSearchPaths*/{}, "Google", "", &FS);
   ASSERT_TRUE((bool)Style1);
   ASSERT_EQ(*Style1, getGoogleStyle());
 }
@@ -1225,19 +1230,19 @@ TEST(ConfigParseTest, GetStyleOfFile) {
                  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);
+  auto Style1 = getStyle("file", "/a/.clang-format", /*StyleSearchPaths*/{}, "Google", "", &FS);
   ASSERT_TRUE((bool)Style1);
   ASSERT_EQ(*Style1, getLLVMStyle());
 
   // Test 2.1: 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);
+  auto Style2 = getStyle("file", "/b/test.cpp", /*StyleSearchPaths*/{}, "Mozilla", "", &FS);
   ASSERT_TRUE((bool)Style2);
   ASSERT_EQ(*Style2, getMozillaStyle());
 
   // Test 2.2: no format on 'none' fallback style.
-  Style2 = getStyle("file", "/b/test.cpp", "none", "", &FS);
+  Style2 = getStyle("file", "/b/test.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE((bool)Style2);
   ASSERT_EQ(*Style2, getNoStyle());
 
@@ -1245,12 +1250,12 @@ TEST(ConfigParseTest, GetStyleOfFile) {
   // 'none'.
   ASSERT_TRUE(FS.addFile("/b/.clang-format", 0,
                          llvm::MemoryBuffer::getMemBuffer("IndentWidth: 2")));
-  Style2 = getStyle("file", "/b/test.cpp", "none", "", &FS);
+  Style2 = getStyle("file", "/b/test.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE((bool)Style2);
   ASSERT_EQ(*Style2, getLLVMStyle());
 
   // Test 2.4: format if yaml with no based style, while fallback is 'none'.
-  Style2 = getStyle("{}", "a.h", "none", "", &FS);
+  Style2 = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE((bool)Style2);
   ASSERT_EQ(*Style2, getLLVMStyle());
 
@@ -1260,23 +1265,24 @@ TEST(ConfigParseTest, GetStyleOfFile) {
                  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);
+  auto Style3 = getStyle("file", "/c/sub/sub/sub/test.cpp", /*StyleSearchPaths*/{}, "LLVM", "", &FS);
   ASSERT_TRUE((bool)Style3);
   ASSERT_EQ(*Style3, getGoogleStyle());
 
   // Test 4: error on invalid fallback style
-  auto Style4 = getStyle("file", "a.h", "KungFu", "", &FS);
+  auto Style4 = getStyle("file", "a.h", /*StyleSearchPaths*/{}, "KungFu", "", &FS);
   ASSERT_FALSE((bool)Style4);
   llvm::consumeError(Style4.takeError());
 
   // Test 5: error on invalid yaml on command line
   auto Style5 = getStyle("{invalid_key=invalid_value}", "a.h", "LLVM", "", &FS,
-                         /*AllowUnknownOptions=*/false, dropDiagnosticHandler);
+                         /*StyleSearchPaths*/{}, /*AllowUnknownOptions=*/false,
+                         dropDiagnosticHandler);
   ASSERT_FALSE((bool)Style5);
   llvm::consumeError(Style5.takeError());
 
   // Test 6: error on invalid style
-  auto Style6 = getStyle("KungFu", "a.h", "LLVM", "", &FS);
+  auto Style6 = getStyle("KungFu", "a.h", /*StyleSearchPaths*/{}, "LLVM", "", &FS);
   ASSERT_FALSE((bool)Style6);
   llvm::consumeError(Style6.takeError());
 
@@ -1288,16 +1294,18 @@ TEST(ConfigParseTest, GetStyleOfFile) {
   ASSERT_TRUE(
       FS.addFile("/d/test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("int i;")));
   auto Style7a = getStyle("file", "/d/.clang-format", "LLVM", "", &FS,
-                          /*AllowUnknownOptions=*/false, dropDiagnosticHandler);
+                          /*StyleSearchPaths*/{}, /*AllowUnknownOptions=*/false,
+                          dropDiagnosticHandler);
   ASSERT_FALSE((bool)Style7a);
   llvm::consumeError(Style7a.takeError());
 
   auto Style7b = getStyle("file", "/d/.clang-format", "LLVM", "", &FS,
-                          /*AllowUnknownOptions=*/true, dropDiagnosticHandler);
+                          /*StyleSearchPaths*/{}, /*AllowUnknownOptions=*/true,
+                          dropDiagnosticHandler);
   ASSERT_TRUE((bool)Style7b);
 
   // Test 8: inferred per-language defaults apply.
-  auto StyleTd = getStyle("file", "x.td", "llvm", "", &FS);
+  auto StyleTd = getStyle("file", "x.td", /*StyleSearchPaths*/{}, "llvm", "", &FS);
   ASSERT_TRUE((bool)StyleTd);
   ASSERT_EQ(*StyleTd, getLLVMStyle(FormatStyle::LK_TableGen));
 
@@ -1309,7 +1317,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
                                        "ColumnLimit: 20")));
   ASSERT_TRUE(FS.addFile("/e/sub/code.cpp", 0,
                          llvm::MemoryBuffer::getMemBuffer("int i;")));
-  auto Style9 = getStyle("file", "/e/sub/code.cpp", "none", "", &FS);
+  auto Style9 = getStyle("file", "/e/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, [] {
     auto Style = getNoStyle();
@@ -1330,7 +1338,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
   NonDefaultWhiteSpaceMacros[1] = "BAR";
 
   ASSERT_NE(Style9->WhitespaceSensitiveMacros, NonDefaultWhiteSpaceMacros);
-  Style9 = getStyle("file", "/e/sub/sub/code.cpp", "none", "", &FS);
+  Style9 = getStyle("file", "/e/sub/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, [&NonDefaultWhiteSpaceMacros] {
     auto Style = getNoStyle();
@@ -1340,7 +1348,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
   }());
 
   // Test 9.2: with LLVM fallback style
-  Style9 = getStyle("file", "/e/sub/code.cpp", "LLVM", "", &FS);
+  Style9 = getStyle("file", "/e/sub/code.cpp", /*StyleSearchPaths*/{}, "LLVM", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, [] {
     auto Style = getLLVMStyle();
@@ -1353,7 +1361,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
       FS.addFile("/e/.clang-format", 0,
                  llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google\n"
                                                   "UseTab: Always")));
-  Style9 = getStyle("file", "/e/sub/code.cpp", "none", "", &FS);
+  Style9 = getStyle("file", "/e/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, [] {
     auto Style = getGoogleStyle();
@@ -1372,26 +1380,26 @@ TEST(ConfigParseTest, GetStyleOfFile) {
   }();
 
   ASSERT_NE(Style9->WhitespaceSensitiveMacros, NonDefaultWhiteSpaceMacros);
-  Style9 = getStyle("file", "/e/sub/sub/code.cpp", "none", "", &FS);
+  Style9 = getStyle("file", "/e/sub/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, SubSubStyle);
 
   // Test 9.5: use InheritParentConfig as style name
   Style9 =
-      getStyle("inheritparentconfig", "/e/sub/sub/code.cpp", "none", "", &FS);
+      getStyle("inheritparentconfig", "/e/sub/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, SubSubStyle);
 
   // Test 9.6: use command line style with inheritance
   Style9 = getStyle("{BasedOnStyle: InheritParentConfig}",
-                    "/e/sub/sub/code.cpp", "none", "", &FS);
+                    "/e/sub/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, SubSubStyle);
 
   // Test 9.7: use command line style with inheritance and own config
   Style9 = getStyle("{BasedOnStyle: InheritParentConfig, "
                     "WhitespaceSensitiveMacros: ['FOO', 'BAR']}",
-                    "/e/sub/code.cpp", "none", "", &FS);
+                    "/e/sub/code.cpp", /*StyleSearchPaths*/{}, "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, SubSubStyle);
 
@@ -1403,7 +1411,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
                  llvm::MemoryBuffer::getMemBuffer(
                      "BasedOnStyle: InheritParentConfig\nIndentWidth: 7")));
   // Make sure we do not use the fallback style
-  Style9 = getStyle("file", "/e/withoutbase/code.cpp", "google", "", &FS);
+  Style9 = getStyle("file", "/e/withoutbase/code.cpp", /*StyleSearchPaths*/{}, "google", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, [] {
     auto Style = getLLVMStyle();
@@ -1411,7 +1419,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
     return Style;
   }());
 
-  Style9 = getStyle("file", "/e/withoutbase/sub/code.cpp", "google", "", &FS);
+  Style9 = getStyle("file", "/e/withoutbase/sub/code.cpp", /*StyleSearchPaths*/{}, "google", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, [] {
     auto Style = getLLVMStyle();
@@ -1421,7 +1429,7 @@ TEST(ConfigParseTest, GetStyleOfFile) {
   }());
 
   // Test 9.9: use inheritance from a specific config file.
-  Style9 = getStyle("file:/e/sub/sub/.clang-format", "/e/sub/sub/code.cpp",
+  Style9 = getStyle("file:/e/sub/sub/.clang-format", "/e/sub/sub/code.cpp", /*StyleSearchPaths*/{},
                     "none", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style9));
   ASSERT_EQ(*Style9, SubSubStyle);
@@ -1439,7 +1447,7 @@ TEST(ConfigParseTest, GetStyleOfSpecificFile) {
   ASSERT_TRUE(FS.addFile("/e/sub/sub/sub/test.cpp", 0,
                          llvm::MemoryBuffer::getMemBuffer("int i;")));
   auto Style = getStyle("file:/e/explicit.clang-format",
-                        "/e/sub/sub/sub/test.cpp", "LLVM", "", &FS);
+                        "/e/sub/sub/sub/test.cpp", /*StyleSearchPaths*/{}, "LLVM", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style));
   ASSERT_EQ(*Style, getGoogleStyle());
 
@@ -1448,12 +1456,12 @@ TEST(ConfigParseTest, GetStyleOfSpecificFile) {
       FS.addFile("../../e/explicit.clang-format", 0,
                  llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: Google")));
   Style = getStyle("file:../../e/explicit.clang-format",
-                   "/e/sub/sub/sub/test.cpp", "LLVM", "", &FS);
+                   "/e/sub/sub/sub/test.cpp", /*StyleSearchPaths*/{}, "LLVM", "", &FS);
   ASSERT_TRUE(static_cast<bool>(Style));
   ASSERT_EQ(*Style, getGoogleStyle());
 
   // Specify path to a format file that does not exist.
-  Style = getStyle("file:/e/missing.clang-format", "/e/sub/sub/sub/test.cpp",
+  Style = getStyle("file:/e/missing.clang-format", "/e/sub/sub/sub/test.cpp", /*StyleSearchPaths*/{},
                    "LLVM", "", &FS);
   ASSERT_FALSE(static_cast<bool>(Style));
   llvm::consumeError(Style.takeError());
@@ -1477,7 +1485,7 @@ TEST(ConfigParseTest, GetStyleOfSpecificFile) {
   CodeFileTest.close();
 
   std::string format_file_arg = std::string("file:") + FormatFilePath.c_str();
-  Style = getStyle(format_file_arg, TestFilePath, "LLVM", "", nullptr);
+  Style = getStyle(format_file_arg, TestFilePath, /*StyleSearchPaths*/{}, "LLVM", "", nullptr);
 
   llvm::sys::fs::remove(FormatFilePath.c_str());
   llvm::sys::fs::remove(TestFilePath.c_str());
diff --git a/clang/unittests/Format/FormatTestObjC.cpp b/clang/unittests/Format/FormatTestObjC.cpp
index 9b6f0c396d4dbf..c692dc0cd8ac87 100644
--- a/clang/unittests/Format/FormatTestObjC.cpp
+++ b/clang/unittests/Format/FormatTestObjC.cpp
@@ -32,7 +32,7 @@ class FormatTestObjC : public FormatTestBase {
 #define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)
 
 TEST(FormatTestObjCStyle, DetectsObjCInStdin) {
-  auto Style = getStyle("LLVM", "<stdin>", "none",
+  auto Style = getStyle("LLVM", "<stdin>", /*StyleSearchPaths*/{}, "none",
                         "@interface\n"
                         "- (id)init;");
   ASSERT_TRUE((bool)Style);
@@ -40,67 +40,67 @@ TEST(FormatTestObjCStyle, DetectsObjCInStdin) {
 }
 
 TEST(FormatTestObjCStyle, DetectsObjCInHeaders) {
-  auto Style = getStyle("LLVM", "a.h", "none",
+  auto Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none",
                         "@interface\n"
                         "- (id)init;");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("LLVM", "a.h", "none",
+  Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none",
                    "@interface\n"
                    "+ (id)init;");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("LLVM", "a.h", "none",
+  Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none",
                    "@interface\n"
                    "@end\n"
                    "//comment");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("LLVM", "a.h", "none",
+  Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none",
                    "@interface\n"
                    "@end //comment");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
   // No recognizable ObjC.
-  Style = getStyle("LLVM", "a.h", "none", "void f() {}");
+  Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none", "void f() {}");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "@interface Foo\n at end");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "@interface Foo\n at end");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none",
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none",
                    "const int interface = 1;\nconst int end = 2;");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "@protocol Foo\n at end");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "@protocol Foo\n at end");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none",
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none",
                    "const int protocol = 1;\nconst int end = 2;");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "typedef NS_ENUM(int, Foo) {};");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "typedef NS_ENUM(int, Foo) {};");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "typedef NS_CLOSED_ENUM(int, Foo) {};");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "typedef NS_CLOSED_ENUM(int, Foo) {};");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "typedef NS_ERROR_ENUM(int, Foo) {};");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "typedef NS_ERROR_ENUM(int, Foo) {};");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", R"objc(
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", R"objc(
 NS_ASSUME_NONNULL_BEGIN
 extern int i;
 NS_ASSUME_NONNULL_END
@@ -108,71 +108,71 @@ NS_ASSUME_NONNULL_END
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", R"objc(
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", R"objc(
 FOUNDATION_EXTERN void DoStuff(void);
 )objc");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", R"objc(
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", R"objc(
 FOUNDATION_EXPORT void DoStuff(void);
 )objc");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "enum Foo {};");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "enum Foo {};");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "inline void Foo() { Log(@\"Foo\"); }");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "inline void Foo() { Log(@\"Foo\"); }");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "inline void Foo() { Log(\"Foo\"); }");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "inline void Foo() { Log(\"Foo\"); }");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
   Style =
-      getStyle("{}", "a.h", "none", "inline void Foo() { id = @[1, 2, 3]; }");
+      getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "inline void Foo() { id = @[1, 2, 3]; }");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none",
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none",
                    "inline void Foo() { id foo = @{1: 2, 3: 4, 5: 6}; }");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none",
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none",
                    "inline void Foo() { int foo[] = {1, 2, 3}; }");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
   // ObjC characteristic types.
-  Style = getStyle("{}", "a.h", "none", "extern NSString *kFoo;");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "extern NSString *kFoo;");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "extern NSInteger Foo();");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "extern NSInteger Foo();");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "NSObject *Foo();");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "NSObject *Foo();");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 
-  Style = getStyle("{}", "a.h", "none", "NSSet *Foo();");
+  Style = getStyle("{}", "a.h", /*StyleSearchPaths*/{}, "none", "NSSet *Foo();");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_ObjC, Style->Language);
 }
 
 TEST(FormatTestObjCStyle, AvoidDetectingDesignatedInitializersAsObjCInHeaders) {
-  auto Style = getStyle("LLVM", "a.h", "none",
+  auto Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none",
                         "static const char *names[] = {[0] = \"foo\",\n"
                         "[kBar] = \"bar\"};");
   ASSERT_TRUE((bool)Style);
   EXPECT_EQ(FormatStyle::LK_Cpp, Style->Language);
 
-  Style = getStyle("LLVM", "a.h", "none",
+  Style = getStyle("LLVM", "a.h", /*StyleSearchPaths*/{}, "none",
                    "static const char *names[] = {[0] EQ \"foo\",\n"
                    "[kBar] EQ \"bar\"};");
   ASSERT_TRUE((bool)Style);
diff --git a/clang/unittests/Format/FormatTestRawStrings.cpp b/clang/unittests/Format/FormatTestRawStrings.cpp
index 0615fb1fad4c53..d2d4773df7736a 100644
--- a/clang/unittests/Format/FormatTestRawStrings.cpp
+++ b/clang/unittests/Format/FormatTestRawStrings.cpp
@@ -136,7 +136,7 @@ TEST_F(FormatTestRawStrings, UsesConfigurationOverBaseStyle) {
   EXPECT_EQ(0, parseConfiguration("---\n"
                                   "Language: Cpp\n"
                                   "BasedOnStyle: Google",
-                                  &Style)
+                                  &Style, /*StyleSearchPaths*/{})
                    .value());
   Style.RawStringFormats = {{
       FormatStyle::LK_Cpp,
diff --git a/clang/unittests/Format/ObjCPropertyAttributeOrderFixerTest.cpp b/clang/unittests/Format/ObjCPropertyAttributeOrderFixerTest.cpp
index 9f852e4768b12b..5fda3b981748d6 100644
--- a/clang/unittests/Format/ObjCPropertyAttributeOrderFixerTest.cpp
+++ b/clang/unittests/Format/ObjCPropertyAttributeOrderFixerTest.cpp
@@ -19,11 +19,13 @@ namespace {
 
 #define CHECK_PARSE(TEXT, FIELD, VALUE)                                        \
   EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!";          \
-  EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_EQ(0, parseConfiguration(TEXT, &Style, /*StyleSearchPaths*/{})        \
+               .value());                                                      \
   EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
 
 #define FAIL_PARSE(TEXT, FIELD, VALUE)                                         \
-  EXPECT_NE(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_NE(0, parseConfiguration(TEXT, &Style, /*StyleSearchPaths*/{})        \
+               .value());                                                      \
   EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
 
 class ObjCPropertyAttributeOrderFixerTest : public FormatTestBase {
diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp
index f9255c6e4c7088..3ed1e5579937f4 100644
--- a/clang/unittests/Format/QualifierFixerTest.cpp
+++ b/clang/unittests/Format/QualifierFixerTest.cpp
@@ -19,11 +19,13 @@ namespace {
 
 #define CHECK_PARSE(TEXT, FIELD, VALUE)                                        \
   EXPECT_NE(VALUE, Style.FIELD) << "Initial value already the same!";          \
-  EXPECT_EQ(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_EQ(0, parseConfiguration(TEXT, &Style, /*StyleSearchPaths*/{})        \
+               .value());                                                      \
   EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
 
 #define FAIL_PARSE(TEXT, FIELD, VALUE)                                         \
-  EXPECT_NE(0, parseConfiguration(TEXT, &Style).value());                      \
+  EXPECT_NE(0, parseConfiguration(TEXT, &Style, /*StyleSearchPaths*/{})        \
+               .value());                                                      \
   EXPECT_EQ(VALUE, Style.FIELD) << "Unexpected value after parsing!"
 
 class QualifierFixerTest : public FormatTestBase {
diff --git a/clang/unittests/Rename/ClangRenameTest.h b/clang/unittests/Rename/ClangRenameTest.h
index 64033657b57963..7b242c26387095 100644
--- a/clang/unittests/Rename/ClangRenameTest.h
+++ b/clang/unittests/Rename/ClangRenameTest.h
@@ -81,7 +81,7 @@ class ClangRenameTest : public testing::Test,
             FileContents))
       return "";
 
-    formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm");
+    formatAndApplyAllReplacements(FileToReplacements, Context.Rewrite, "llvm", /*StyleSearchPaths*/{});
     return Context.getRewrittenText(InputFileID);
   }
 
diff --git a/clang/unittests/Tooling/RefactoringTest.cpp b/clang/unittests/Tooling/RefactoringTest.cpp
index 77d410f5d3b604..cf3c7c7fa1e137 100644
--- a/clang/unittests/Tooling/RefactoringTest.cpp
+++ b/clang/unittests/Tooling/RefactoringTest.cpp
@@ -541,7 +541,8 @@ TEST_F(ReplacementTest, MultipleFilesReplaceAndFormat) {
                             "10")});
   EXPECT_TRUE(
       formatAndApplyAllReplacements(FileToReplaces, Context.Rewrite,
-                                    "{BasedOnStyle: LLVM, ColumnLimit: 20}"));
+                                    "{BasedOnStyle: LLVM, ColumnLimit: 20}",
+                                    /*StyleSearchPaths*/{}));
   EXPECT_EQ(Expected1, Context.getRewrittenText(ID1));
   EXPECT_EQ(Expected2, Context.getRewrittenText(ID2));
 }
diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h
index 1d04783753d5cd..04dc9ccca36150 100644
--- a/llvm/include/llvm/Support/YAMLTraits.h
+++ b/llvm/include/llvm/Support/YAMLTraits.h
@@ -779,6 +779,8 @@ class IO {
   IO(void *Ctxt = nullptr);
   virtual ~IO();
 
+  virtual SourceMgr& getSourceMgr();
+
   virtual bool outputting() const = 0;
 
   virtual unsigned beginSequence() = 0;
@@ -819,6 +821,7 @@ class IO {
 
   virtual void setError(const Twine &) = 0;
   virtual void setAllowUnknownKeys(bool Allow);
+  virtual bool allowUnknownKeys() const;
 
   template <typename T>
   void enumCase(T &Val, const char* Str, const T ConstVal) {
@@ -1449,6 +1452,8 @@ class Input : public IO {
   // Check if there was an syntax or semantic error during parsing.
   std::error_code error();
 
+  SourceMgr& getSourceMgr() override;
+
 private:
   bool outputting() const override;
   bool mapTag(StringRef, bool) override;
@@ -1567,6 +1572,7 @@ class Input : public IO {
   const Node *getCurrentNode() const;
 
   void setAllowUnknownKeys(bool Allow) override;
+  bool allowUnknownKeys() const override;
 
 private:
   SourceMgr                           SrcMgr; // must be before Strm
diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp
index 56b557646100b1..d7bc0255fe4445 100644
--- a/llvm/lib/Support/YAMLTraits.cpp
+++ b/llvm/lib/Support/YAMLTraits.cpp
@@ -39,6 +39,10 @@ IO::IO(void *Context) : Ctxt(Context) {}
 
 IO::~IO() = default;
 
+SourceMgr& IO::getSourceMgr() {
+  llvm_unreachable("Only supported for Input");
+}
+
 void *IO::getContext() const {
   return Ctxt;
 }
@@ -51,6 +55,10 @@ void IO::setAllowUnknownKeys(bool Allow) {
   llvm_unreachable("Only supported for Input");
 }
 
+bool IO::allowUnknownKeys() const {
+  llvm_unreachable("Only supported for Input");
+}
+
 //===----------------------------------------------------------------------===//
 //  Input
 //===----------------------------------------------------------------------===//
@@ -75,6 +83,8 @@ Input::~Input() = default;
 
 std::error_code Input::error() { return EC; }
 
+SourceMgr& Input::getSourceMgr() { return SrcMgr; }
+
 bool Input::outputting() const {
   return false;
 }
@@ -473,6 +483,8 @@ void Input::setError(const Twine &Message) {
 
 void Input::setAllowUnknownKeys(bool Allow) { AllowUnknownKeys = Allow; }
 
+bool Input::allowUnknownKeys() const { return AllowUnknownKeys; }
+
 bool Input::canElideEmptySequence() {
   return false;
 }



More information about the cfe-commits mailing list