[clang compat] Harden handling of 'final' specifier

Clang 9f57b65a272817752aa00e2fb94154e6eed1d0ec sometimes prints the 'final'
keyword twice for a declaration (tracking bug:
https://github.com/llvm/llvm-project/issues/56517).

This triggered several bugs in MungedForwardDeclareLineForTemplates:

* Only removed first 'final'
* Removed one character too many (sizeof(char[]) includes the trailing NUL)

Instead, replace all occurrences of 'final' and do it first so the stripping of
superclasses and body also get rid of trailing spaces. This should now work even
if the upstream bug is fixed.
This commit is contained in:
Kim Gräsman 2022-07-13 21:04:00 +02:00
parent 979002bf8e
commit 7ca0a75b85
2 changed files with 16 additions and 9 deletions

View File

@ -457,25 +457,24 @@ string MungedForwardDeclareLineForTemplates(const TemplateDecl* decl) {
raw_string_ostream ostream(line);
decl->print(ostream); // calls DeclPrinter
line = ostream.str();
// Remove "final" specifier which isn't needed for forward
// declarations.
ReplaceAll(&line, " final ", " ");
// Get rid of the superclasses, if any (this will nix the body too).
line = Split(line, " :", 2)[0];
// Get rid of the template body, if any (true if no superclasses).
line = Split(line, " {", 2)[0];
// Remove "final" specifier which isn't needed for forward
// declarations.
const char kFinalSpecifier[] = " final ";
string::size_type final_pos = line.find(kFinalSpecifier);
if (final_pos != string::npos) {
line.replace(final_pos, sizeof(kFinalSpecifier), " ");
}
// The template name is now the last word on the line. Replace it
// by its fully-qualified form.
const string::size_type name = line.rfind(' ');
CHECK_(name != string::npos && "Unexpected printable template-type");
return PrintForwardDeclare(decl, line.substr(0, name), GlobalFlags().cxx17ns);
line = line.substr(0, name);
return PrintForwardDeclare(decl, line, GlobalFlags().cxx17ns);
}
string MungedForwardDeclareLine(const NamedDecl* decl) {

View File

@ -119,6 +119,14 @@ inline void StripWhiteSpace(string* str) {
StripWhiteSpaceRight(str);
}
inline void ReplaceAll(std::string* str, const std::string& from,
const std::string& to) {
for (size_t pos = str->find(from); pos != std::string::npos;
pos = str->find(from, pos + to.length())) {
str->replace(pos, from.length(), to);
}
}
// This is the same as split() in Python. If max_segs is 0, there's
// no limit on the number of the generated segments.
inline vector<string> Split(