[clang-tools-extra] [clangd] Add padding to struct hover information (PR #115665)

2024-11-10 Thread Kevin Kremer via cfe-commits

https://github.com/Xoltus updated 
https://github.com/llvm/llvm-project/pull/115665

>From 3b64d9d82047159fbd7cb4662d1b666c4431be9c Mon Sep 17 00:00:00 2001
From: Kevin Kremer 
Date: Sun, 10 Nov 2024 16:00:00 +
Subject: [PATCH 1/2] [clangd] Add padding to struct hover information

HI.Padding is already available for a struct's member
variables but the struct itself is not displaying how
much padding has been added to it.

This commit sums up all padding within a struct and adds
it to a struct's hover information.
---
 clang-tools-extra/clangd/Hover.cpp| 27 
 .../clangd/unittests/HoverTests.cpp   | 62 +++
 2 files changed, 89 insertions(+)

diff --git a/clang-tools-extra/clangd/Hover.cpp 
b/clang-tools-extra/clangd/Hover.cpp
index 298fa79e3fd0ba..9ef32a777d73fe 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1006,6 +1006,33 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
   HI.Size = Size->getQuantity() * 8;
 if (!RD->isDependentType() && RD->isCompleteDefinition())
   HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl());
+if (HI.Size && !RD->field_empty()) {
+  HI.Padding = 0;
+  const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+  auto NumFields = std::distance(RD->field_begin(), RD->field_end());
+  auto FieldIt = RD->field_begin();
+  for (; --NumFields; ++FieldIt) {
+unsigned Offset = Layout.getFieldOffset(FieldIt->getFieldIndex());
+unsigned NextOffset =
+Layout.getFieldOffset(FieldIt->getFieldIndex() + 1);
+if (auto Size = Ctx.getTypeSizeInCharsIfKnown(FieldIt->getType())) {
+  unsigned EndOfField = Offset + Size->getQuantity() * 8;
+  if (NextOffset > EndOfField)
+HI.Padding = *HI.Padding + NextOffset - EndOfField;
+} else {
+  HI.Padding.reset();
+  break;
+}
+  }
+  // We've processed all but the last field. If we still have valid
+  // HI.Padding, finish the calculation
+  auto Size = Ctx.getTypeSizeInCharsIfKnown(FieldIt->getType());
+  if (HI.Padding && Size) {
+unsigned Offset = Layout.getFieldOffset(FieldIt->getFieldIndex());
+HI.Padding = *HI.Padding + *HI.Size - Offset - Size->getQuantity() * 8;
+  }
+}
+
 return;
   }
 
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp 
b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 69f6df46c87ce0..96fb4d8f317328 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -73,6 +73,68 @@ TEST(Hover, Structured) {
  HI.Type = "void ()";
  HI.Parameters.emplace();
}},
+  {R"cpp(
+struct [[F^oo]] {
+  char a;
+  long long b;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 128;
+ HI.Padding = 56;
+ HI.Align = 64;
+   }},
+  {R"cpp(
+struct [[F^oo]] {
+  int b;
+  char a;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 64;
+ HI.Padding = 24;
+ HI.Align = 32;
+   }},
+  {R"cpp(
+struct [[F^oo]] {
+  double a;
+  char b;
+  double c;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 192;
+ HI.Padding = 46;
+ HI.Align = 64;
+   }},  {R"cpp(
+struct [[F^oo]] {
+  double a;
+  char b;
+  double c;
+  char d;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 256;
+ HI.Padding = 112;
+ HI.Align = 64;
+   }},
   // Field
   {R"cpp(
   namespace ns1 { namespace ns2 {

>From 126fb9bf3e5bef3026bee37c4147ba36857bdeb8 Mon Sep 17 00:00:00 2001
From: Kevin Kremer 
Date: Mon, 11 Nov 2024 04:01:15 +
Subject: [PATCH 2/2] fix formatting

---
 clang-tools-extra/clangd/unittests/HoverTests.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp 
b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 96fb4d8f317328..269b1f2faf5059 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-t

[clang-tools-extra] [clangd] Add padding to struct hover information (PR #115665)

2024-11-10 Thread Kevin Kremer via cfe-commits

https://github.com/Xoltus created 
https://github.com/llvm/llvm-project/pull/115665

Hi team, I've written a small patch as a small quality of life improvement for 
my development and figured it may be worth sharing. Please let me know what you 
think:

HI.Padding is already available for a struct's member variables but the struct 
itself is not displaying how much padding has been added to it. This commit 
sums up all padding within a struct and adds it to a struct's hover information.

```
struct Foo
{
char a;
int b;
char c;
};
```
results in
![Screenshot 2024-11-10 at 9 50 52 
AM](https://github.com/user-attachments/assets/163d1582-4de0-4673-9024-8f04465f221a)

I've also added additional tests to HoverTests.cpp.

>From 3b64d9d82047159fbd7cb4662d1b666c4431be9c Mon Sep 17 00:00:00 2001
From: Kevin Kremer 
Date: Sun, 10 Nov 2024 16:00:00 +
Subject: [PATCH] [clangd] Add padding to struct hover information

HI.Padding is already available for a struct's member
variables but the struct itself is not displaying how
much padding has been added to it.

This commit sums up all padding within a struct and adds
it to a struct's hover information.
---
 clang-tools-extra/clangd/Hover.cpp| 27 
 .../clangd/unittests/HoverTests.cpp   | 62 +++
 2 files changed, 89 insertions(+)

diff --git a/clang-tools-extra/clangd/Hover.cpp 
b/clang-tools-extra/clangd/Hover.cpp
index 298fa79e3fd0ba..9ef32a777d73fe 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -1006,6 +1006,33 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
   HI.Size = Size->getQuantity() * 8;
 if (!RD->isDependentType() && RD->isCompleteDefinition())
   HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl());
+if (HI.Size && !RD->field_empty()) {
+  HI.Padding = 0;
+  const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+  auto NumFields = std::distance(RD->field_begin(), RD->field_end());
+  auto FieldIt = RD->field_begin();
+  for (; --NumFields; ++FieldIt) {
+unsigned Offset = Layout.getFieldOffset(FieldIt->getFieldIndex());
+unsigned NextOffset =
+Layout.getFieldOffset(FieldIt->getFieldIndex() + 1);
+if (auto Size = Ctx.getTypeSizeInCharsIfKnown(FieldIt->getType())) {
+  unsigned EndOfField = Offset + Size->getQuantity() * 8;
+  if (NextOffset > EndOfField)
+HI.Padding = *HI.Padding + NextOffset - EndOfField;
+} else {
+  HI.Padding.reset();
+  break;
+}
+  }
+  // We've processed all but the last field. If we still have valid
+  // HI.Padding, finish the calculation
+  auto Size = Ctx.getTypeSizeInCharsIfKnown(FieldIt->getType());
+  if (HI.Padding && Size) {
+unsigned Offset = Layout.getFieldOffset(FieldIt->getFieldIndex());
+HI.Padding = *HI.Padding + *HI.Size - Offset - Size->getQuantity() * 8;
+  }
+}
+
 return;
   }
 
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp 
b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 69f6df46c87ce0..96fb4d8f317328 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -73,6 +73,68 @@ TEST(Hover, Structured) {
  HI.Type = "void ()";
  HI.Parameters.emplace();
}},
+  {R"cpp(
+struct [[F^oo]] {
+  char a;
+  long long b;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 128;
+ HI.Padding = 56;
+ HI.Align = 64;
+   }},
+  {R"cpp(
+struct [[F^oo]] {
+  int b;
+  char a;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 64;
+ HI.Padding = 24;
+ HI.Align = 32;
+   }},
+  {R"cpp(
+struct [[F^oo]] {
+  double a;
+  char b;
+  double c;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 192;
+ HI.Padding = 46;
+ HI.Align = 64;
+   }},  {R"cpp(
+struct [[F^oo]] {
+  double a;
+  char b;
+  double c;
+  char d;
+};
+  )cpp",
+   [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.Name = "Foo";
+ HI.Kind = index::SymbolKind::Struct;
+ HI.Definition = "struct Foo {}";
+ HI.Size = 256;