[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