[clang-format] Support inheriting from more than 1 parents in the fallback case

Currently, we are unable to inherit from a chain of parent configs where the outermost parent config has `BasedOnStyle: InheritParentConfig` set. This patch adds a test case for this scenario, and adds support for it.

To illustrate, suppose we have the following directory structure:
```
- e/
  |- .clang-format (BasedOnStyle: InheritParentConfig) <-- outermost config
  |- sub/
    |- .clang-format (BasedOnStyle: InheritParentConfig)
    |- sub/
      |- .clang-format (BasedOnStyle: InheritParentConfig)
      |- code.cpp
```
Now consider what happens when we run `clang-format --style=file /e/sub/sub/code.cpp`.

Without this patch, on a release build, only the innermost config will be applied. On a debug build, clang-format crashes due to an assertion failure.
With this patch, clang-format behaves as we'd expect, applying all 3 configs.

Reviewed By: HazardyKnusperkeks, curdeius

Differential Revision: https://reviews.llvm.org/D116371
This commit is contained in:
Zhao Wei Liew 2022-01-03 11:30:24 +01:00 committed by Marek Kurdej
parent 791523bae6
commit 0090cd4e7a
2 changed files with 35 additions and 29 deletions

View File

@ -3288,6 +3288,16 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
auto dropDiagnosticHandler = [](const llvm::SMDiagnostic &, void *) {};
auto applyChildFormatTexts = [&](FormatStyle *Style) {
for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) {
auto EC = parseConfiguration(*MemBuf, Style, AllowUnknownOptions,
dropDiagnosticHandler);
// It was already correctly parsed.
assert(!EC);
static_cast<void>(EC);
}
};
for (StringRef Directory = Path; !Directory.empty();
Directory = llvm::sys::path::parent_path(Directory)) {
@ -3330,14 +3340,7 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
return Style;
LLVM_DEBUG(llvm::dbgs() << "Applying child configurations\n");
for (const auto &MemBuf : llvm::reverse(ChildFormatTextToApply)) {
auto Ec = parseConfiguration(*MemBuf, &Style, AllowUnknownOptions,
dropDiagnosticHandler);
// It was already correctly parsed.
assert(!Ec);
static_cast<void>(Ec);
}
applyChildFormatTexts(&Style);
return Style;
}
@ -3363,17 +3366,9 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName,
UnsuitableConfigFiles);
if (!ChildFormatTextToApply.empty()) {
assert(ChildFormatTextToApply.size() == 1);
LLVM_DEBUG(llvm::dbgs()
<< "Applying child configuration on fallback style\n");
auto Ec =
parseConfiguration(*ChildFormatTextToApply.front(), &FallbackStyle,
AllowUnknownOptions, dropDiagnosticHandler);
// It was already correctly parsed.
assert(!Ec);
static_cast<void>(Ec);
<< "Applying child configurations on fallback style\n");
applyChildFormatTexts(&FallbackStyle);
}
return FallbackStyle;

View File

@ -21464,8 +21464,8 @@ TEST(FormatStyle, GetStyleOfFile) {
ASSERT_TRUE((bool)StyleTd);
ASSERT_EQ(*StyleTd, getLLVMStyle(FormatStyle::LK_TableGen));
// Test 9.1: overwriting a file style, when parent no file exists with no
// fallback style
// Test 9.1.1: overwriting a file style, when no parent file exists with no
// fallback style.
ASSERT_TRUE(FS.addFile(
"/e/sub/.clang-format", 0,
llvm::MemoryBuffer::getMemBuffer("BasedOnStyle: InheritParentConfig\n"
@ -21480,6 +21480,25 @@ TEST(FormatStyle, GetStyleOfFile) {
return Style;
}());
// Test 9.1.2: propagate more than one level with no parent file.
ASSERT_TRUE(FS.addFile("/e/sub/sub/code.cpp", 0,
llvm::MemoryBuffer::getMemBuffer("int i;")));
ASSERT_TRUE(FS.addFile("/e/sub/sub/.clang-format", 0,
llvm::MemoryBuffer::getMemBuffer(
"BasedOnStyle: InheritParentConfig\n"
"WhitespaceSensitiveMacros: ['FOO', 'BAR']")));
std::vector<std::string> NonDefaultWhiteSpaceMacros{"FOO", "BAR"};
ASSERT_NE(Style9->WhitespaceSensitiveMacros, NonDefaultWhiteSpaceMacros);
Style9 = getStyle("file", "/e/sub/sub/code.cpp", "none", "", &FS);
ASSERT_TRUE(static_cast<bool>(Style9));
ASSERT_EQ(*Style9, [&NonDefaultWhiteSpaceMacros] {
auto Style = getNoStyle();
Style.ColumnLimit = 20;
Style.WhitespaceSensitiveMacros = NonDefaultWhiteSpaceMacros;
return Style;
}());
// Test 9.2: with LLVM fallback style
Style9 = getStyle("file", "/e/sub/code.cpp", "LLVM", "", &FS);
ASSERT_TRUE(static_cast<bool>(Style9));
@ -21503,15 +21522,7 @@ TEST(FormatStyle, GetStyleOfFile) {
return Style;
}());
// Test 9.4: propagate more than one level
ASSERT_TRUE(FS.addFile("/e/sub/sub/code.cpp", 0,
llvm::MemoryBuffer::getMemBuffer("int i;")));
ASSERT_TRUE(FS.addFile("/e/sub/sub/.clang-format", 0,
llvm::MemoryBuffer::getMemBuffer(
"BasedOnStyle: InheritParentConfig\n"
"WhitespaceSensitiveMacros: ['FOO', 'BAR']")));
std::vector<std::string> NonDefaultWhiteSpaceMacros{"FOO", "BAR"};
// Test 9.4: propagate more than one level with a parent file.
const auto SubSubStyle = [&NonDefaultWhiteSpaceMacros] {
auto Style = getGoogleStyle();
Style.ColumnLimit = 20;