[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-25 Thread Aleksandr Platonov via cfe-commits

ArcsinX wrote:

> LGTM if @ArcsinX is happy.

I didn't look at the implementation code closely, but I checked that from a 
functionality point of view everything works as expected

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits

schuay wrote:

And done. PR text updated to mention AI assistance. Added bitfield tests, and 
skipped bitfields via `ResultBuilder::IsOffsetofField`.

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits

https://github.com/schuay updated 
https://github.com/llvm/llvm-project/pull/195126

>From edd263a699c37dd2dca16a5abce9cba228d059e3 Mon Sep 17 00:00:00 2001
From: Jakob Linke 
Date: Thu, 30 Apr 2026 18:46:52 +0200
Subject: [PATCH] [clang] Complete fields in __builtin_offsetof designators

Code completion was a no-op inside __builtin_offsetof: a cursor at
__builtin_offsetof(T, ^) or __builtin_offsetof(T, a.^) fell through
to ordinary-name completion instead of suggesting fields. Route the
code_completion token to a new SemaCodeCompletion entry point that
walks the designator path so far, resolves the subobject's type, and
enumerates its members. Methods are filtered out, inherited fields
are included, indirect fields from anonymous unions and structs are
peeled, and `using Base::field` resolves through its UsingShadowDecl.
A code_completion token past a complete component (right after `]`
or at the end of the chain) is dropped rather than offering fields
the user can't paste without first typing `.`.

The offsetof and designated-initializer type walkers are folded into
one helper parameterized by a field-lookup callback, which
incidentally fixes reference-field and indirect-field traversal in
designated-initializer completion too.

Tests: lit cases in offsetof.cpp covering empty/dot/array/inheritance/
reference/anonymous/using-shadow/macro forms, extended desig-init.cpp
walker cases, and a clangd unit test exercising the IDE path.
---
 .../clangd/unittests/CodeCompleteTests.cpp|  39 +
 clang/include/clang/Sema/SemaCodeCompletion.h |   3 +
 clang/lib/Parse/ParseExpr.cpp |  40 +-
 clang/lib/Sema/SemaCodeComplete.cpp   | 133 +++---
 clang/test/CodeCompletion/desig-init.cpp  |  34 +
 clang/test/CodeCompletion/offsetof.cpp| 128 +
 6 files changed, 356 insertions(+), 21 deletions(-)
 create mode 100644 clang/test/CodeCompletion/offsetof.cpp

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 386ffb54924a7..109156fa4d176 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -2539,6 +2539,45 @@ TEST(CompletionTest, CodeCompletionContext) {
   EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
 }
 
+TEST(CompletionTest, OffsetOfDesignator) {
+  auto Results = completions(R"cpp(
+struct S { int field; int other; void fieldFn(); };
+int x = __builtin_offsetof(S, fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+  EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
+
+  Results = completions(R"cpp(
+struct Inner { int field; void fieldFn(); };
+struct Outer { Inner inner; };
+int x = __builtin_offsetof(Outer, inner.fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+
+  Results = completions(R"cpp(
+struct Inner { int field; void fieldFn(); };
+struct Outer { Inner inner[2]; };
+int i;
+int x = __builtin_offsetof(Outer, inner[i].fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+
+  Results = completions(R"cpp(
+struct Base { int field; void fieldFn(); };
+struct Derived : Base {};
+int x = __builtin_offsetof(Derived, fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+}
+
 TEST(CompletionTest, FixItForArrowToDot) {
   MockFS FS;
   MockCompilationDatabase CDB;
diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h 
b/clang/include/clang/Sema/SemaCodeCompletion.h
index abdfb51900318..7203b19d58898 100644
--- a/clang/include/clang/Sema/SemaCodeCompletion.h
+++ b/clang/include/clang/Sema/SemaCodeCompletion.h
@@ -154,6 +154,9 @@ class SemaCodeCompletion : public SemaBase {
   void CodeCompleteDesignator(const QualType BaseType,
   llvm::ArrayRef InitExprs,
   const Designation &D);
+  /// Trigger code completion for a position inside a __builtin_offsetof
+  /// member designator (after the type's `,`, or after a `.`).
+  void CodeCompleteOffsetOfDesignator(QualType BaseType, const Designation &D);
   void CodeCompleteKeywordAfterIf(bool AfterExclaim) const;
   void CodeCompleteAfterIf(Scope *S, bool IsBracedThen);
 
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index c3ac8d7e6eb74..34e0d7905cd23 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2407,7 +2407,18 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
   return ExprError();
 }
 
+auto TriggerCompletion = [&](const Designation &D) {
+   

[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits

https://github.com/schuay edited 
https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits

schuay wrote:

> Please disclose AI usage in PR description.
> 
> https://llvm.org/docs/AIToolPolicy.html

Will do, wasn't aware of this.

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Yanzuo Liu via cfe-commits

zwuis wrote:

Please disclose AI usage in PR description.

https://llvm.org/docs/AIToolPolicy.html

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits

schuay wrote:

Thanks for the review! Pushed a follow-up commit that filters bit-fields from 
the offsetof completion (since they are not valid as the second argument; 
`err_offsetof_bitfield`) and adds tests for both direct and indirect 
(anonymous-member) bit-fields.

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits


@@ -1670,6 +1675,11 @@ bool ResultBuilder::IsMember(const NamedDecl *ND) const {
  isa(ND);
 }
 
+bool ResultBuilder::IsField(const NamedDecl *ND) const {
+  ND = ND->getUnderlyingDecl();
+  return isa(ND) || isa(ND);

schuay wrote:

Good suggestion. After adding the bit-field filter (the other review comment), 
the function needs to inspect the cast result to call `isBitField()`, so I 
switched it to `dyn_cast` instead. Let me know if you'd prefer a different 
shape.

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Jakob Linke via cfe-commits

https://github.com/schuay updated 
https://github.com/llvm/llvm-project/pull/195126

>From a804b4d51fc4720e54d894dab4fc99938cdf2a0b Mon Sep 17 00:00:00 2001
From: Jakob Linke 
Date: Thu, 30 Apr 2026 18:46:52 +0200
Subject: [PATCH 1/2] [clang] Complete fields in __builtin_offsetof designators

Code completion was a no-op inside __builtin_offsetof: a cursor at
__builtin_offsetof(T, ^) or __builtin_offsetof(T, a.^) fell through
to ordinary-name completion instead of suggesting fields. Route the
code_completion token to a new SemaCodeCompletion entry point that
walks the designator path so far, resolves the subobject's type, and
enumerates its members. Methods are filtered out, inherited fields
are included, indirect fields from anonymous unions and structs are
peeled, and `using Base::field` resolves through its UsingShadowDecl.
A code_completion token past a complete component (right after `]`
or at the end of the chain) is dropped rather than offering fields
the user can't paste without first typing `.`.

The offsetof and designated-initializer type walkers are folded into
one helper parameterized by a field-lookup callback, which
incidentally fixes reference-field and indirect-field traversal in
designated-initializer completion too.

Tests: lit cases in offsetof.cpp covering empty/dot/array/inheritance/
reference/anonymous/using-shadow/macro forms, extended desig-init.cpp
walker cases, and a clangd unit test exercising the IDE path.
---
 .../clangd/unittests/CodeCompleteTests.cpp|  39 ++
 clang/include/clang/Sema/SemaCodeCompletion.h |   3 +
 clang/lib/Parse/ParseExpr.cpp |  40 +-
 clang/lib/Sema/SemaCodeComplete.cpp   | 127 +++---
 clang/test/CodeCompletion/desig-init.cpp  |  34 +
 clang/test/CodeCompletion/offsetof.cpp|  95 +
 6 files changed, 317 insertions(+), 21 deletions(-)
 create mode 100644 clang/test/CodeCompletion/offsetof.cpp

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 386ffb54924a7..109156fa4d176 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -2539,6 +2539,45 @@ TEST(CompletionTest, CodeCompletionContext) {
   EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
 }
 
+TEST(CompletionTest, OffsetOfDesignator) {
+  auto Results = completions(R"cpp(
+struct S { int field; int other; void fieldFn(); };
+int x = __builtin_offsetof(S, fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+  EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
+
+  Results = completions(R"cpp(
+struct Inner { int field; void fieldFn(); };
+struct Outer { Inner inner; };
+int x = __builtin_offsetof(Outer, inner.fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+
+  Results = completions(R"cpp(
+struct Inner { int field; void fieldFn(); };
+struct Outer { Inner inner[2]; };
+int i;
+int x = __builtin_offsetof(Outer, inner[i].fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+
+  Results = completions(R"cpp(
+struct Base { int field; void fieldFn(); };
+struct Derived : Base {};
+int x = __builtin_offsetof(Derived, fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+}
+
 TEST(CompletionTest, FixItForArrowToDot) {
   MockFS FS;
   MockCompilationDatabase CDB;
diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h 
b/clang/include/clang/Sema/SemaCodeCompletion.h
index abdfb51900318..7203b19d58898 100644
--- a/clang/include/clang/Sema/SemaCodeCompletion.h
+++ b/clang/include/clang/Sema/SemaCodeCompletion.h
@@ -154,6 +154,9 @@ class SemaCodeCompletion : public SemaBase {
   void CodeCompleteDesignator(const QualType BaseType,
   llvm::ArrayRef InitExprs,
   const Designation &D);
+  /// Trigger code completion for a position inside a __builtin_offsetof
+  /// member designator (after the type's `,`, or after a `.`).
+  void CodeCompleteOffsetOfDesignator(QualType BaseType, const Designation &D);
   void CodeCompleteKeywordAfterIf(bool AfterExclaim) const;
   void CodeCompleteAfterIf(Scope *S, bool IsBracedThen);
 
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index c3ac8d7e6eb74..34e0d7905cd23 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2407,7 +2407,18 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
   return ExprError();
 }
 
+auto TriggerCompletion = [&](const Designation &D) {
+  

[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis edited https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis commented:

Could you please add tests with bit-fields, which should not be the second 
argument of `offsetof`?

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-05-07 Thread Yanzuo Liu via cfe-commits


@@ -1670,6 +1675,11 @@ bool ResultBuilder::IsMember(const NamedDecl *ND) const {
  isa(ND);
 }
 
+bool ResultBuilder::IsField(const NamedDecl *ND) const {
+  ND = ND->getUnderlyingDecl();
+  return isa(ND) || isa(ND);

zwuis wrote:

```cpp
isa(ND)
```

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-04-30 Thread Jakob Linke via cfe-commits

https://github.com/schuay edited 
https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-04-30 Thread Jakob Linke via cfe-commits

schuay wrote:

cc @ArcsinX 

https://github.com/llvm/llvm-project/pull/195126
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang] Complete fields in __builtin_offsetof designators (PR #195126)

2026-04-30 Thread Jakob Linke via cfe-commits

https://github.com/schuay updated 
https://github.com/llvm/llvm-project/pull/195126

>From a804b4d51fc4720e54d894dab4fc99938cdf2a0b Mon Sep 17 00:00:00 2001
From: Jakob Linke 
Date: Thu, 30 Apr 2026 18:46:52 +0200
Subject: [PATCH] [clang] Complete fields in __builtin_offsetof designators

Code completion was a no-op inside __builtin_offsetof: a cursor at
__builtin_offsetof(T, ^) or __builtin_offsetof(T, a.^) fell through
to ordinary-name completion instead of suggesting fields. Route the
code_completion token to a new SemaCodeCompletion entry point that
walks the designator path so far, resolves the subobject's type, and
enumerates its members. Methods are filtered out, inherited fields
are included, indirect fields from anonymous unions and structs are
peeled, and `using Base::field` resolves through its UsingShadowDecl.
A code_completion token past a complete component (right after `]`
or at the end of the chain) is dropped rather than offering fields
the user can't paste without first typing `.`.

The offsetof and designated-initializer type walkers are folded into
one helper parameterized by a field-lookup callback, which
incidentally fixes reference-field and indirect-field traversal in
designated-initializer completion too.

Tests: lit cases in offsetof.cpp covering empty/dot/array/inheritance/
reference/anonymous/using-shadow/macro forms, extended desig-init.cpp
walker cases, and a clangd unit test exercising the IDE path.
---
 .../clangd/unittests/CodeCompleteTests.cpp|  39 ++
 clang/include/clang/Sema/SemaCodeCompletion.h |   3 +
 clang/lib/Parse/ParseExpr.cpp |  40 +-
 clang/lib/Sema/SemaCodeComplete.cpp   | 127 +++---
 clang/test/CodeCompletion/desig-init.cpp  |  34 +
 clang/test/CodeCompletion/offsetof.cpp|  95 +
 6 files changed, 317 insertions(+), 21 deletions(-)
 create mode 100644 clang/test/CodeCompletion/offsetof.cpp

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 386ffb54924a7..109156fa4d176 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -2539,6 +2539,45 @@ TEST(CompletionTest, CodeCompletionContext) {
   EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
 }
 
+TEST(CompletionTest, OffsetOfDesignator) {
+  auto Results = completions(R"cpp(
+struct S { int field; int other; void fieldFn(); };
+int x = __builtin_offsetof(S, fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+  EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
+
+  Results = completions(R"cpp(
+struct Inner { int field; void fieldFn(); };
+struct Outer { Inner inner; };
+int x = __builtin_offsetof(Outer, inner.fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+
+  Results = completions(R"cpp(
+struct Inner { int field; void fieldFn(); };
+struct Outer { Inner inner[2]; };
+int i;
+int x = __builtin_offsetof(Outer, inner[i].fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+
+  Results = completions(R"cpp(
+struct Base { int field; void fieldFn(); };
+struct Derived : Base {};
+int x = __builtin_offsetof(Derived, fiel^d);
+  )cpp");
+  EXPECT_THAT(
+  Results.Completions,
+  ElementsAre(AllOf(named("field"), kind(CompletionItemKind::Field;
+}
+
 TEST(CompletionTest, FixItForArrowToDot) {
   MockFS FS;
   MockCompilationDatabase CDB;
diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h 
b/clang/include/clang/Sema/SemaCodeCompletion.h
index abdfb51900318..7203b19d58898 100644
--- a/clang/include/clang/Sema/SemaCodeCompletion.h
+++ b/clang/include/clang/Sema/SemaCodeCompletion.h
@@ -154,6 +154,9 @@ class SemaCodeCompletion : public SemaBase {
   void CodeCompleteDesignator(const QualType BaseType,
   llvm::ArrayRef InitExprs,
   const Designation &D);
+  /// Trigger code completion for a position inside a __builtin_offsetof
+  /// member designator (after the type's `,`, or after a `.`).
+  void CodeCompleteOffsetOfDesignator(QualType BaseType, const Designation &D);
   void CodeCompleteKeywordAfterIf(bool AfterExclaim) const;
   void CodeCompleteAfterIf(Scope *S, bool IsBracedThen);
 
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index c3ac8d7e6eb74..34e0d7905cd23 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -2407,7 +2407,18 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
   return ExprError();
 }
 
+auto TriggerCompletion = [&](const Designation &D) {
+