Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3727,6 +3727,11 @@ the configuration (without a prefix: ``Auto``).
namespace Extra {
}}}

.. _ConfigFile:

**ConfigFile** (``String``) :versionbadge:`clang-format 20` :ref:`¶ <ConfigFile>`
Specify the absolute or relative path of another config file to process.

.. _ConstructorInitializerAllOnOneLineOrOnePerLine:

**ConstructorInitializerAllOnOneLineOrOnePerLine** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <ConstructorInitializerAllOnOneLineOrOnePerLine>`
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2481,6 +2481,10 @@ struct FormatStyle {
/// \version 5
bool CompactNamespaces;

/// Specify the absolute or relative path of another config file to process.
/// \version 20
std::string ConfigFile;

/// This option is **deprecated**. See ``CurrentLine`` of
/// ``PackConstructorInitializers``.
/// \version 3.7
Expand Down Expand Up @@ -5195,6 +5199,7 @@ struct FormatStyle {
BreakTemplateDeclarations == R.BreakTemplateDeclarations &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
CompactNamespaces == R.CompactNamespaces &&
ConfigFile == R.ConfigFile &&
ConstructorInitializerIndentWidth ==
R.ConstructorInitializerIndentWidth &&
ContinuationIndentWidth == R.ContinuationIndentWidth &&
Expand Down
46 changes: 43 additions & 3 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("TemplateNames", Style.TemplateNames);
IO.mapOptional("TypeNames", Style.TypeNames);
IO.mapOptional("TypenameMacros", Style.TypenameMacros);
IO.mapOptional("ConfigFile", Style.ConfigFile);
IO.mapOptional("UseTab", Style.UseTab);
IO.mapOptional("VerilogBreakBetweenInstancePorts",
Style.VerilogBreakBetweenInstancePorts);
Expand Down Expand Up @@ -2046,6 +2047,13 @@ ParseError validateQualifierOrder(FormatStyle *Style) {
return ParseError::Success;
}

llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
loadAndParseConfigFile(StringRef ConfigFile, llvm::vfs::FileSystem *FS,
FormatStyle *Style, bool AllowUnknownOptions,
llvm::SourceMgr::DiagHandlerTy DiagHandler);

static constexpr StringRef Source{"<command-line>"};

std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
FormatStyle *Style, bool AllowUnknownOptions,
llvm::SourceMgr::DiagHandlerTy DiagHandler,
Expand Down Expand Up @@ -2107,8 +2115,41 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
// See comment on FormatStyle::TSC_Wrapped.
return make_error_code(ParseError::BinPackTrailingCommaConflict);
}
if (Style->QualifierAlignment != FormatStyle::QAS_Leave)
return make_error_code(validateQualifierOrder(Style));
if (Style->QualifierAlignment != FormatStyle::QAS_Leave) {
const auto EC = validateQualifierOrder(Style);
if (EC != ParseError::Success)
return make_error_code(EC);
}
if (!Style->InheritsParentConfig && !Style->ConfigFile.empty()) {
auto *FS = llvm::vfs::getRealFileSystem().get();
assert(FS);
SmallString<128> ConfigFile{Style->ConfigFile};
Style->ConfigFile.clear();
switch (ConfigFile[0]) {
case '~':
llvm::sys::fs::expand_tilde(ConfigFile, ConfigFile);
break;
case '/':
break;
default: {
const auto BufferId = Config.getBufferIdentifier();
if (BufferId == Source) {
llvm::sys::fs::make_absolute(ConfigFile);
} else {
llvm::sys::fs::make_absolute(llvm::sys::path::parent_path(BufferId),
ConfigFile);
}
}
}
if (!llvm::sys::fs::exists(ConfigFile)) {
llvm::errs() << ConfigFile << ": " << "file not found\n";
return make_error_code(ParseError::Error);
}
const auto Text = loadAndParseConfigFile(ConfigFile, FS, Style,
AllowUnknownOptions, DiagHandler);
if (Text.getError())
return make_error_code(ParseError::Error);
}
return make_error_code(ParseError::Success);
}

Expand Down Expand Up @@ -4032,7 +4073,6 @@ Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,

if (StyleName.starts_with("{")) {
// Parse YAML/JSON style from the command line.
StringRef Source = "<command-line>";
if (std::error_code ec =
parseConfiguration(llvm::MemoryBufferRef(StyleName, Source), &Style,
AllowUnknownOptions, DiagHandler)) {
Expand Down