[llvm-branch-commits] [clang] release/21.x: [clang-format] Correctly handle backward compatibility of C headers (#159908) (PR #163910)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Oct 16 22:18:03 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-format
Author: None (llvmbot)
<details>
<summary>Changes</summary>
Backport d7921de8027eec19a9d272bf445944973e6758b1
Requested by: @<!-- -->owenca
---
Full diff: https://github.com/llvm/llvm-project/pull/163910.diff
2 Files Affected:
- (modified) clang/lib/Format/Format.cpp (+53-38)
- (modified) clang/unittests/Format/ConfigParseTest.cpp (+6-3)
``````````diff
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 161a6c4b47e7f..d4e3a1989cd71 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -2133,47 +2133,68 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
if (Input.error())
return Input.error();
- for (unsigned i = 0; i < Styles.size(); ++i) {
- // Ensures that only the first configuration can skip the Language option.
- if (Styles[i].Language == FormatStyle::LK_None && i != 0)
+ assert(!Styles.empty());
+ const auto StyleCount = Styles.size();
+
+ // Start from the second style as (only) the first one may be the default.
+ for (unsigned I = 1; I < StyleCount; ++I) {
+ const auto Lang = Styles[I].Language;
+ if (Lang == FormatStyle::LK_None)
return make_error_code(ParseError::Error);
// Ensure that each language is configured at most once.
- for (unsigned j = 0; j < i; ++j) {
- if (Styles[i].Language == Styles[j].Language) {
+ for (unsigned J = 0; J < I; ++J) {
+ if (Lang == Styles[J].Language) {
LLVM_DEBUG(llvm::dbgs()
<< "Duplicate languages in the config file on positions "
- << j << " and " << i << "\n");
+ << J << " and " << I << '\n');
return make_error_code(ParseError::Error);
}
}
}
- // Look for a suitable configuration starting from the end, so we can
- // find the configuration for the specific language first, and the default
- // configuration (which can only be at slot 0) after it.
- FormatStyle::FormatStyleSet StyleSet;
- bool LanguageFound = false;
- for (const FormatStyle &Style : llvm::reverse(Styles)) {
- const auto Lang = Style.Language;
- if (Lang != FormatStyle::LK_None)
- StyleSet.Add(Style);
- if (Lang == Language ||
- // For backward compatibility.
- (Lang == FormatStyle::LK_Cpp && Language == FormatStyle::LK_C)) {
- LanguageFound = true;
- } else if (IsDotHFile && Language == FormatStyle::LK_Cpp &&
- (Lang == FormatStyle::LK_C || Lang == FormatStyle::LK_ObjC)) {
- Language = Lang;
- LanguageFound = true;
+
+ int LanguagePos = -1; // Position of the style for Language.
+ int CppPos = -1; // Position of the style for C++.
+ int CPos = -1; // Position of the style for C.
+
+ // Search Styles for Language and store the positions of C++ and C styles in
+ // case Language is not found.
+ for (unsigned I = 0; I < StyleCount; ++I) {
+ const auto Lang = Styles[I].Language;
+ if (Lang == Language) {
+ LanguagePos = I;
+ break;
}
- }
- if (!LanguageFound) {
- if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
+ if (Lang == FormatStyle::LK_Cpp)
+ CppPos = I;
+ else if (Lang == FormatStyle::LK_C)
+ CPos = I;
+ }
+
+ // If Language is not found, use the default style if there is one. Otherwise,
+ // use the C style for C++ .h files and for backward compatibility, the C++
+ // style for .c files.
+ if (LanguagePos < 0) {
+ if (Styles[0].Language == FormatStyle::LK_None) // Default style.
+ LanguagePos = 0;
+ else if (IsDotHFile && Language == FormatStyle::LK_Cpp)
+ LanguagePos = CPos;
+ else if (!IsDotHFile && Language == FormatStyle::LK_C)
+ LanguagePos = CppPos;
+ if (LanguagePos < 0)
return make_error_code(ParseError::Unsuitable);
- FormatStyle DefaultStyle = Styles[0];
- DefaultStyle.Language = Language;
- StyleSet.Add(std::move(DefaultStyle));
}
- *Style = *StyleSet.Get(Language);
+
+ for (const auto &S : llvm::reverse(llvm::drop_begin(Styles)))
+ Style->StyleSet.Add(S);
+
+ *Style = Styles[LanguagePos];
+
+ if (LanguagePos == 0) {
+ if (Style->Language == FormatStyle::LK_None) // Default style.
+ Style->Language = Language;
+ Style->StyleSet.Add(*Style);
+ }
+
if (Style->InsertTrailingCommas != FormatStyle::TCS_None &&
Style->BinPackArguments) {
// See comment on FormatStyle::TSC_Wrapped.
@@ -2204,14 +2225,8 @@ FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
if (!Styles)
return std::nullopt;
auto It = Styles->find(Language);
- if (It == Styles->end()) {
- if (Language != FormatStyle::LK_C)
- return std::nullopt;
- // For backward compatibility.
- It = Styles->find(FormatStyle::LK_Cpp);
- if (It == Styles->end())
- return std::nullopt;
- }
+ if (It == Styles->end())
+ return std::nullopt;
FormatStyle Style = It->second;
Style.StyleSet = *this;
return Style;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 2b17c36f6aa84..bbe1923e19ee1 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -1269,7 +1269,7 @@ TEST(ConfigParseTest, AllowCppForC) {
ParseError::Success);
}
-TEST(ConfigParseTest, HandleNonCppDotHFile) {
+TEST(ConfigParseTest, HandleDotHFile) {
FormatStyle Style = {};
Style.Language = FormatStyle::LK_Cpp;
EXPECT_EQ(parseConfiguration("Language: C", &Style,
@@ -1280,11 +1280,14 @@ TEST(ConfigParseTest, HandleNonCppDotHFile) {
Style = {};
Style.Language = FormatStyle::LK_Cpp;
- EXPECT_EQ(parseConfiguration("Language: ObjC", &Style,
+ EXPECT_EQ(parseConfiguration("Language: Cpp\n"
+ "...\n"
+ "Language: C",
+ &Style,
/*AllowUnknownOptions=*/false,
/*IsDotHFile=*/true),
ParseError::Success);
- EXPECT_EQ(Style.Language, FormatStyle::LK_ObjC);
+ EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
}
TEST(ConfigParseTest, UsesLanguageForBasedOnStyle) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/163910
More information about the llvm-branch-commits
mailing list