-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[Clang] adjust caret placement for the suggested attribute location for enum class #168092
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-clang Author: Oleksandr T. (a-tarasyuk) ChangesFixes #163224 This patch addresses the issue by correcting the caret insertion location for attributes incorrectly positioned before For example: [[nodiscard]] enum class E1 {};is now suggested as: enum class [[nodiscard]] E1 {};Full diff: https://github.com/llvm/llvm-project/pull/168092.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 88a05affebf9e..06195b5086a66 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -420,6 +420,8 @@ Improvements to Clang's diagnostics
or continue (#GH166013)
- Clang now emits a diagnostic in case `vector_size` or `ext_vector_type`
attributes are used with a negative size (#GH165463).
+- Clang now provides correct caret placement when attributes appear before
+ `enum class` (#GH163224).
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index a6fc676f23a51..5bf366db7f509 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1100,30 +1100,32 @@ Parser::DeclGroupPtrTy Parser::ParseDeclOrFunctionDefInternal(
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
- auto LengthOfTSTToken = [](DeclSpec::TST TKind) {
- assert(DeclSpec::isDeclRep(TKind));
- switch(TKind) {
- case DeclSpec::TST_class:
- return 5;
- case DeclSpec::TST_struct:
- return 6;
- case DeclSpec::TST_union:
- return 5;
- case DeclSpec::TST_enum:
- return 4;
- case DeclSpec::TST_interface:
- return 9;
- default:
- llvm_unreachable("we only expect to get the length of the class/struct/union/enum");
+ auto GetAdjustedAttrsLoc = [&]() {
+ auto TKind = DS.getTypeSpecType();
+ if (!DeclSpec::isDeclRep(TKind))
+ return SourceLocation();
+
+ if (TKind == DeclSpec::TST_enum) {
+ const auto *ED = dyn_cast_or_null<EnumDecl>(DS.getRepAsDecl());
+ if (ED && ED->isScoped()) {
+ const auto &SM = Actions.getSourceManager();
+ const auto &LangOpts = Actions.getLangOpts();
+ auto End = Lexer::getLocForEndOfToken(DS.getTypeSpecTypeLoc(),
+ /*Offset*/ 0, SM, LangOpts);
+ auto NextToken = Lexer::findNextToken(End, SM, LangOpts);
+ if (NextToken)
+ return NextToken->getEndLoc();
+ }
}
+ const auto &Policy = Actions.getASTContext().getPrintingPolicy();
+ unsigned Offset =
+ StringRef(DeclSpec::getSpecifierName(TKind, Policy)).size();
+ return DS.getTypeSpecTypeLoc().getLocWithOffset(Offset);
};
+
// Suggest correct location to fix '[[attrib]] struct' to 'struct [[attrib]]'
- SourceLocation CorrectLocationForAttributes =
- DeclSpec::isDeclRep(DS.getTypeSpecType())
- ? DS.getTypeSpecTypeLoc().getLocWithOffset(
- LengthOfTSTToken(DS.getTypeSpecType()))
- : SourceLocation();
+ SourceLocation CorrectLocationForAttributes = GetAdjustedAttrsLoc();
ProhibitAttributes(Attrs, CorrectLocationForAttributes);
ConsumeToken();
RecordDecl *AnonRecord = nullptr;
diff --git a/clang/test/FixIt/fixit-cxx0x-attributes.cpp b/clang/test/FixIt/fixit-cxx0x-attributes.cpp
new file mode 100644
index 0000000000000..f64b6530efa15
--- /dev/null
+++ b/clang/test/FixIt/fixit-cxx0x-attributes.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -fno-diagnostics-show-line-numbers %s 2>&1 | FileCheck %s -strict-whitespace
+
+[[nodiscard]] enum class E1 { };
+// expected-error@-1 {{misplaced attributes; expected attributes here}}
+// CHECK: {{^}}{{\[\[}}nodiscard]] enum class E1 { };
+// CHECK: {{^}}~~~~~~~~~~~~~ ^
+// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
+// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:25-[[@LINE-5]]:25}:"{{\[\[}}nodiscard]]"
+
+[[nodiscard]] enum struct E2 { };
+// expected-error@-1 {{misplaced attributes; expected attributes here}}
+// CHECK: {{^}}{{\[\[}}nodiscard]] enum struct E2 { };
+// CHECK: {{^}}~~~~~~~~~~~~~ ^
+// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
+// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:26-[[@LINE-5]]:26}:"{{\[\[}}nodiscard]]"
+
+[[nodiscard]] enum class E3 { };
+// expected-error@-1 {{misplaced attributes; expected attributes here}}
+// CHECK: {{^}}{{\[\[}}nodiscard]] enum class E3 { };
+// CHECK: {{^}}~~~~~~~~~~~~~ ^
+// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
+// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:34-[[@LINE-5]]:34}:"{{\[\[}}nodiscard]]"
+
+[[nodiscard]] enum /*comment*/ class E4 { };
+// expected-error@-1 {{misplaced attributes; expected attributes here}}
+// CHECK: {{^}}{{\[\[}}nodiscard]] enum /*comment*/ class E4 { };
+// CHECK: {{^}}~~~~~~~~~~~~~ ^
+// CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:15}:""
+// CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:38-[[@LINE-5]]:38}:"{{\[\[}}nodiscard]]"
|
erichkeane
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few nits, + want a few tests, else I think this is about right.
erichkeane
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 nit, else LGTM
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
… into fix/163224
AaronBallman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Fixes #163224
This patch addresses the issue by correcting the caret insertion location for attributes incorrectly positioned before an enum. The location is now derived from the associated
EnumDecl: for named enums, the attribute is placed before the identifier, while for anonymous enum definitions, it is placed before the opening brace, with a fallback to the semicolon when no brace is present.For example:
is now suggested as: