Skip to content

Commit faca424

Browse files
owencac-rhodes
authored andcommitted
[clang-format] Correctly handle backward compatibility of C headers (llvm#159908)
This in effect reverts 05fb840 and 7e1a88b, the latter of which erroneously changed the behavior of formatting `ObjC` header files when both the default and `ObjC` styles were absent. Now the previous behavior of treating that as an error is restored. Fixes llvm#158704 (cherry picked from commit d7921de)
1 parent c5a3aa8 commit faca424

File tree

2 files changed

+59
-41
lines changed

2 files changed

+59
-41
lines changed

clang/lib/Format/Format.cpp

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,47 +2133,68 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config,
21332133
if (Input.error())
21342134
return Input.error();
21352135

2136-
for (unsigned i = 0; i < Styles.size(); ++i) {
2137-
// Ensures that only the first configuration can skip the Language option.
2138-
if (Styles[i].Language == FormatStyle::LK_None && i != 0)
2136+
assert(!Styles.empty());
2137+
const auto StyleCount = Styles.size();
2138+
2139+
// Start from the second style as (only) the first one may be the default.
2140+
for (unsigned I = 1; I < StyleCount; ++I) {
2141+
const auto Lang = Styles[I].Language;
2142+
if (Lang == FormatStyle::LK_None)
21392143
return make_error_code(ParseError::Error);
21402144
// Ensure that each language is configured at most once.
2141-
for (unsigned j = 0; j < i; ++j) {
2142-
if (Styles[i].Language == Styles[j].Language) {
2145+
for (unsigned J = 0; J < I; ++J) {
2146+
if (Lang == Styles[J].Language) {
21432147
LLVM_DEBUG(llvm::dbgs()
21442148
<< "Duplicate languages in the config file on positions "
2145-
<< j << " and " << i << "\n");
2149+
<< J << " and " << I << '\n');
21462150
return make_error_code(ParseError::Error);
21472151
}
21482152
}
21492153
}
2150-
// Look for a suitable configuration starting from the end, so we can
2151-
// find the configuration for the specific language first, and the default
2152-
// configuration (which can only be at slot 0) after it.
2153-
FormatStyle::FormatStyleSet StyleSet;
2154-
bool LanguageFound = false;
2155-
for (const FormatStyle &Style : llvm::reverse(Styles)) {
2156-
const auto Lang = Style.Language;
2157-
if (Lang != FormatStyle::LK_None)
2158-
StyleSet.Add(Style);
2159-
if (Lang == Language ||
2160-
// For backward compatibility.
2161-
(Lang == FormatStyle::LK_Cpp && Language == FormatStyle::LK_C)) {
2162-
LanguageFound = true;
2163-
} else if (IsDotHFile && Language == FormatStyle::LK_Cpp &&
2164-
(Lang == FormatStyle::LK_C || Lang == FormatStyle::LK_ObjC)) {
2165-
Language = Lang;
2166-
LanguageFound = true;
2154+
2155+
int LanguagePos = -1; // Position of the style for Language.
2156+
int CppPos = -1; // Position of the style for C++.
2157+
int CPos = -1; // Position of the style for C.
2158+
2159+
// Search Styles for Language and store the positions of C++ and C styles in
2160+
// case Language is not found.
2161+
for (unsigned I = 0; I < StyleCount; ++I) {
2162+
const auto Lang = Styles[I].Language;
2163+
if (Lang == Language) {
2164+
LanguagePos = I;
2165+
break;
21672166
}
2168-
}
2169-
if (!LanguageFound) {
2170-
if (Styles.empty() || Styles[0].Language != FormatStyle::LK_None)
2167+
if (Lang == FormatStyle::LK_Cpp)
2168+
CppPos = I;
2169+
else if (Lang == FormatStyle::LK_C)
2170+
CPos = I;
2171+
}
2172+
2173+
// If Language is not found, use the default style if there is one. Otherwise,
2174+
// use the C style for C++ .h files and for backward compatibility, the C++
2175+
// style for .c files.
2176+
if (LanguagePos < 0) {
2177+
if (Styles[0].Language == FormatStyle::LK_None) // Default style.
2178+
LanguagePos = 0;
2179+
else if (IsDotHFile && Language == FormatStyle::LK_Cpp)
2180+
LanguagePos = CPos;
2181+
else if (!IsDotHFile && Language == FormatStyle::LK_C)
2182+
LanguagePos = CppPos;
2183+
if (LanguagePos < 0)
21712184
return make_error_code(ParseError::Unsuitable);
2172-
FormatStyle DefaultStyle = Styles[0];
2173-
DefaultStyle.Language = Language;
2174-
StyleSet.Add(std::move(DefaultStyle));
21752185
}
2176-
*Style = *StyleSet.Get(Language);
2186+
2187+
for (const auto &S : llvm::reverse(llvm::drop_begin(Styles)))
2188+
Style->StyleSet.Add(S);
2189+
2190+
*Style = Styles[LanguagePos];
2191+
2192+
if (LanguagePos == 0) {
2193+
if (Style->Language == FormatStyle::LK_None) // Default style.
2194+
Style->Language = Language;
2195+
Style->StyleSet.Add(*Style);
2196+
}
2197+
21772198
if (Style->InsertTrailingCommas != FormatStyle::TCS_None &&
21782199
Style->BinPackArguments) {
21792200
// See comment on FormatStyle::TSC_Wrapped.
@@ -2204,14 +2225,8 @@ FormatStyle::FormatStyleSet::Get(FormatStyle::LanguageKind Language) const {
22042225
if (!Styles)
22052226
return std::nullopt;
22062227
auto It = Styles->find(Language);
2207-
if (It == Styles->end()) {
2208-
if (Language != FormatStyle::LK_C)
2209-
return std::nullopt;
2210-
// For backward compatibility.
2211-
It = Styles->find(FormatStyle::LK_Cpp);
2212-
if (It == Styles->end())
2213-
return std::nullopt;
2214-
}
2228+
if (It == Styles->end())
2229+
return std::nullopt;
22152230
FormatStyle Style = It->second;
22162231
Style.StyleSet = *this;
22172232
return Style;

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,7 +1269,7 @@ TEST(ConfigParseTest, AllowCppForC) {
12691269
ParseError::Success);
12701270
}
12711271

1272-
TEST(ConfigParseTest, HandleNonCppDotHFile) {
1272+
TEST(ConfigParseTest, HandleDotHFile) {
12731273
FormatStyle Style = {};
12741274
Style.Language = FormatStyle::LK_Cpp;
12751275
EXPECT_EQ(parseConfiguration("Language: C", &Style,
@@ -1280,11 +1280,14 @@ TEST(ConfigParseTest, HandleNonCppDotHFile) {
12801280

12811281
Style = {};
12821282
Style.Language = FormatStyle::LK_Cpp;
1283-
EXPECT_EQ(parseConfiguration("Language: ObjC", &Style,
1283+
EXPECT_EQ(parseConfiguration("Language: Cpp\n"
1284+
"...\n"
1285+
"Language: C",
1286+
&Style,
12841287
/*AllowUnknownOptions=*/false,
12851288
/*IsDotHFile=*/true),
12861289
ParseError::Success);
1287-
EXPECT_EQ(Style.Language, FormatStyle::LK_ObjC);
1290+
EXPECT_EQ(Style.Language, FormatStyle::LK_Cpp);
12881291
}
12891292

12901293
TEST(ConfigParseTest, UsesLanguageForBasedOnStyle) {

0 commit comments

Comments
 (0)