Correct newline emission in generated headers

Eliminates extraneous newlines between top-level Objective-C declarations in `-emit-objc-header` headers. Specifically, there should now always be exactly one—no more, no less—empty line between `@end` and whatever follows it.

Besides being more aesthetically pleasing, this eliminates ordering-dependent behavior where PrintAsClang would print an extra newline when visiting an empty extension, which meant that the order in which empty and non-empty extensions were visited during printing could result in whitespace differences in the compiler output. Printing the blank line is now conditional on whether `tell()` indicates that characters were actually written to the output.

Fixes rdar://143533893.
This commit is contained in:
Becca Royal-Gordon
2025-01-24 16:26:33 -08:00
parent e689ad3cf3
commit 60f6afb76c
7 changed files with 58 additions and 64 deletions

View File

@@ -488,7 +488,6 @@ public:
(inserted || !it->second.second))
ClangValueTypePrinter::forwardDeclType(os, CD, printer);
it->second = {EmissionState::Defined, true};
os << '\n';
printer.print(CD);
return true;
}
@@ -507,7 +506,6 @@ public:
forwardDeclareType(TD);
});
os << '\n';
printer.print(FD);
return true;
}
@@ -550,7 +548,6 @@ public:
return false;
seenTypes[PD] = { EmissionState::Defined, true };
os << '\n';
printer.print(PD);
return true;
}
@@ -576,7 +573,6 @@ public:
if (!forwardDeclareMemberTypes(ED->getAllMembers(), ED))
return false;
os << '\n';
printer.print(ED);
return true;
}
@@ -840,6 +836,7 @@ public:
while (!declsToWrite.empty()) {
const Decl *D = declsToWrite.back();
bool success = true;
auto posBefore = os.tell();
if (auto ED = dyn_cast<EnumDecl>(D)) {
success = writeEnum(ED);
@@ -870,7 +867,10 @@ public:
if (success) {
assert(declsToWrite.back() == D);
os << "\n";
// If we actually wrote something to the file, add a newline after it.
// (As opposed to, for instance, an extension we decided to skip.)
if (posBefore != os.tell())
os << "\n";
declsToWrite.pop_back();
}
}