Skip to content

Commit 71c0784

Browse files
authored
Fix the double space and double attribute printing of the final keyword. (#88600)
Fixes #56517.
1 parent 562f061 commit 71c0784

File tree

5 files changed

+57
-27
lines changed

5 files changed

+57
-27
lines changed

clang/lib/AST/DeclPrinter.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ namespace {
119119
void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
120120
const TemplateParameterList *Params);
121121
enum class AttrPosAsWritten { Default = 0, Left, Right };
122-
void
122+
bool
123123
prettyPrintAttributes(const Decl *D,
124124
AttrPosAsWritten Pos = AttrPosAsWritten::Default);
125125
void prettyPrintPragmas(Decl *D);
@@ -252,16 +252,19 @@ static DeclPrinter::AttrPosAsWritten getPosAsWritten(const Attr *A,
252252
return DeclPrinter::AttrPosAsWritten::Right;
253253
}
254254

255-
void DeclPrinter::prettyPrintAttributes(const Decl *D,
255+
// returns true if an attribute was printed.
256+
bool DeclPrinter::prettyPrintAttributes(const Decl *D,
256257
AttrPosAsWritten Pos /*=Default*/) {
257-
if (Policy.PolishForDeclaration)
258-
return;
258+
bool hasPrinted = false;
259259

260260
if (D->hasAttrs()) {
261261
const AttrVec &Attrs = D->getAttrs();
262262
for (auto *A : Attrs) {
263263
if (A->isInherited() || A->isImplicit())
264264
continue;
265+
// Print out the keyword attributes, they aren't regular attributes.
266+
if (Policy.PolishForDeclaration && !A->isKeywordAttribute())
267+
continue;
265268
switch (A->getKind()) {
266269
#define ATTR(X)
267270
#define PRAGMA_SPELLING_ATTR(X) case attr::X:
@@ -275,13 +278,15 @@ void DeclPrinter::prettyPrintAttributes(const Decl *D,
275278
if (Pos != AttrPosAsWritten::Left)
276279
Out << ' ';
277280
A->printPretty(Out, Policy);
281+
hasPrinted = true;
278282
if (Pos == AttrPosAsWritten::Left)
279283
Out << ' ';
280284
}
281285
break;
282286
}
283287
}
284288
}
289+
return hasPrinted;
285290
}
286291

287292
void DeclPrinter::prettyPrintPragmas(Decl *D) {
@@ -1065,12 +1070,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
10651070
// FIXME: add printing of pragma attributes if required.
10661071
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
10671072
Out << "__module_private__ ";
1068-
Out << D->getKindName();
10691073

1070-
prettyPrintAttributes(D);
1074+
Out << D->getKindName() << ' ';
10711075

1072-
if (D->getIdentifier()) {
1076+
// FIXME: Move before printing the decl kind to match the behavior of the
1077+
// attribute printing for variables and function where they are printed first.
1078+
if (prettyPrintAttributes(D, AttrPosAsWritten::Left))
10731079
Out << ' ';
1080+
1081+
if (D->getIdentifier()) {
10741082
if (auto *NNS = D->getQualifier())
10751083
NNS->print(Out, Policy);
10761084
Out << *D;
@@ -1087,16 +1095,13 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
10871095
}
10881096
}
10891097

1090-
if (D->hasDefinition()) {
1091-
if (D->hasAttr<FinalAttr>()) {
1092-
Out << " final";
1093-
}
1094-
}
1098+
prettyPrintAttributes(D, AttrPosAsWritten::Right);
10951099

10961100
if (D->isCompleteDefinition()) {
1101+
Out << ' ';
10971102
// Print the base classes
10981103
if (D->getNumBases()) {
1099-
Out << " : ";
1104+
Out << ": ";
11001105
for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
11011106
BaseEnd = D->bases_end(); Base != BaseEnd; ++Base) {
11021107
if (Base != D->bases_begin())
@@ -1115,14 +1120,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
11151120
if (Base->isPackExpansion())
11161121
Out << "...";
11171122
}
1123+
Out << ' ';
11181124
}
11191125

11201126
// Print the class definition
11211127
// FIXME: Doesn't print access specifiers, e.g., "public:"
11221128
if (Policy.TerseOutput) {
1123-
Out << " {}";
1129+
Out << "{}";
11241130
} else {
1125-
Out << " {\n";
1131+
Out << "{\n";
11261132
VisitDeclContext(D);
11271133
Indent() << "}";
11281134
}

clang/test/SemaCXX/cxx11-attr-print.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,8 @@ template struct S<int>;
8787

8888
// CHECK: using Small2 {{\[}}[gnu::mode(byte)]] = int;
8989
using Small2 [[gnu::mode(byte)]] = int;
90+
91+
class FinalNonTemplate final {};
92+
// CHECK: class FinalNonTemplate final {
93+
template <typename T> class FinalTemplate final {};
94+
// CHECK: template <typename T> class FinalTemplate final {

clang/test/SemaHLSL/BuiltIns/RWBuffers.hlsl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ typedef vector<float, 3> float3;
66
RWBuffer<float3> Buffer;
77

88
// expected-error@+2 {{class template 'RWBuffer' requires template arguments}}
9-
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class RWBuffer final}}
9+
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class RWBuffer}}
1010
RWBuffer BufferErr1;
1111

1212
// expected-error@+2 {{too few template arguments for class template 'RWBuffer'}}
13-
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class RWBuffer final}}
13+
// expected-note@*:* {{template declaration from hidden source: template <class element_type> class RWBuffer}}
1414
RWBuffer<> BufferErr2;
1515

1616
[numthreads(1,1,1)]

clang/unittests/AST/DeclPrinterTest.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,13 @@ ::testing::AssertionResult PrintedDeclCXX11Matches(StringRef Code,
8686
ExpectedPrinted, "input.cc");
8787
}
8888

89-
::testing::AssertionResult PrintedDeclCXX11Matches(
90-
StringRef Code,
91-
const DeclarationMatcher &NodeMatch,
92-
StringRef ExpectedPrinted) {
89+
::testing::AssertionResult
90+
PrintedDeclCXX11Matches(StringRef Code, const DeclarationMatcher &NodeMatch,
91+
StringRef ExpectedPrinted,
92+
PrintingPolicyAdjuster PolicyModifier = nullptr) {
9393
std::vector<std::string> Args(1, "-std=c++11");
94-
return PrintedDeclMatches(Code,
95-
Args,
96-
NodeMatch,
97-
ExpectedPrinted,
98-
"input.cc");
94+
return PrintedDeclMatches(Code, Args, NodeMatch, ExpectedPrinted, "input.cc",
95+
PolicyModifier);
9996
}
10097

10198
::testing::AssertionResult PrintedDeclCXX11nonMSCMatches(
@@ -1555,3 +1552,25 @@ TEST(DeclPrinter, VarDeclWithInitializer) {
15551552
PrintedDeclCXX17Matches("void foo() {int arr[42]; for(int a : arr);}",
15561553
namedDecl(hasName("a")).bind("id"), "int a"));
15571554
}
1555+
1556+
TEST(DeclPrinter, TestTemplateFinal) {
1557+
// By default we should print 'final' keyword whether class is implicitly or
1558+
// explicitly marked final.
1559+
ASSERT_TRUE(PrintedDeclCXX11Matches(
1560+
"template<typename T>\n"
1561+
"class FinalTemplate final {};",
1562+
classTemplateDecl(hasName("FinalTemplate")).bind("id"),
1563+
"template <typename T> class FinalTemplate final {}"));
1564+
}
1565+
1566+
TEST(DeclPrinter, TestTemplateFinalWithPolishForDecl) {
1567+
// clangd relies on the 'final' keyword being printed when
1568+
// PolishForDeclaration is enabled, so make sure it is even if implicit attrs
1569+
// are disabled.
1570+
ASSERT_TRUE(PrintedDeclCXX11Matches(
1571+
"template<typename T>\n"
1572+
"class FinalTemplate final {};",
1573+
classTemplateDecl(hasName("FinalTemplate")).bind("id"),
1574+
"template <typename T> class FinalTemplate final {}",
1575+
[](PrintingPolicy &Policy) { Policy.PolishForDeclaration = true; }));
1576+
}

clang/utils/TableGen/ClangAttrEmitter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1608,7 +1608,7 @@ writePrettyPrintFunction(const Record &R,
16081608
Prefix = "[";
16091609
Suffix = "]";
16101610
} else if (Variety == "Keyword") {
1611-
Prefix = " ";
1611+
Prefix = "";
16121612
Suffix = "";
16131613
} else if (Variety == "Pragma") {
16141614
Prefix = "#pragma ";

0 commit comments

Comments
 (0)