Skip to content

Commit

Permalink
[clangd] Show alignment for records and fields decls (#67213)
Browse files Browse the repository at this point in the history
Shows align for records and fields declarations in hover information.

Example:
```cpp
struct A {
  char a;
  short b;
};
```

For this struct hover informations shows:
```
Size: 4 bytes, alignment 2 bytes
```


![image](https://github.com/llvm/llvm-project/assets/12231048/a130b353-f3f6-4203-b0d7-3d592b7a7855)
  • Loading branch information
sr-tream committed Oct 22, 2023
1 parent 4f56d47 commit c300884
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 2 deletions.
5 changes: 5 additions & 0 deletions clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,8 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
if (auto *RD = llvm::dyn_cast<RecordDecl>(&ND)) {
if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RD->getTypeForDecl()))
HI.Size = Size->getQuantity() * 8;
if (!RD->isDependentType() && RD->isCompleteDefinition())
HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl());
return;
}

Expand All @@ -1009,6 +1011,7 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
if (Record)
Record = Record->getDefinition();
if (Record && !Record->isInvalidDecl() && !Record->isDependentType()) {
HI.Align = Ctx.getTypeAlign(FD->getType());
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Record);
HI.Offset = Layout.getFieldOffset(FD->getFieldIndex());
if (FD->isBitField())
Expand Down Expand Up @@ -1487,6 +1490,8 @@ markup::Document HoverInfo::present() const {
P.appendText(
llvm::formatv(" (+{0} padding)", formatSize(*Padding)).str());
}
if (Align)
P.appendText(", alignment " + formatSize(*Align));
}

if (CalleeArgInfo) {
Expand Down
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/Hover.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ struct HoverInfo {
std::optional<uint64_t> Offset;
/// Contains the padding following a field within the enclosing class.
std::optional<uint64_t> Padding;
/// Contains the alignment of fields and types where it's interesting.
std::optional<uint64_t> Align;
// Set when symbol is inside function call. Contains information extracted
// from the callee definition about the argument this is passed as.
std::optional<Param> CalleeArgInfo;
Expand Down
13 changes: 11 additions & 2 deletions clang-tools-extra/clangd/unittests/HoverTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ TEST(Hover, Structured) {
HI.Offset = 0;
HI.Size = 8;
HI.Padding = 56;
HI.Align = 8;
HI.AccessSpecifier = "private";
}},
// Union field
Expand All @@ -110,6 +111,7 @@ TEST(Hover, Structured) {
HI.Type = "char";
HI.Size = 8;
HI.Padding = 120;
HI.Align = 8;
HI.AccessSpecifier = "public";
}},
// Bitfield
Expand All @@ -128,6 +130,7 @@ TEST(Hover, Structured) {
HI.Type = "int";
HI.Offset = 0;
HI.Size = 1;
HI.Align = 32;
HI.AccessSpecifier = "public";
}},
// Local to class method.
Expand Down Expand Up @@ -192,6 +195,7 @@ TEST(Hover, Structured) {
HI.Type = "char";
HI.Offset = 0;
HI.Size = 8;
HI.Align = 8;
HI.AccessSpecifier = "public";
}},
// Struct definition shows size.
Expand All @@ -204,6 +208,7 @@ TEST(Hover, Structured) {
HI.Kind = index::SymbolKind::Struct;
HI.Definition = "struct X {}";
HI.Size = 8;
HI.Align = 8;
}},
// Variable with template type
{R"cpp(
Expand Down Expand Up @@ -1375,6 +1380,7 @@ class Foo final {})cpp";
HI.Offset = 8;
HI.Size = 1;
HI.Padding = 23;
HI.Align = 8;
HI.AccessSpecifier = "public";
}}};
for (const auto &Case : Cases) {
Expand Down Expand Up @@ -1411,6 +1417,7 @@ class Foo final {})cpp";
EXPECT_EQ(H->Value, Expected.Value);
EXPECT_EQ(H->Size, Expected.Size);
EXPECT_EQ(H->Offset, Expected.Offset);
EXPECT_EQ(H->Align, Expected.Align);
EXPECT_EQ(H->AccessSpecifier, Expected.AccessSpecifier);
EXPECT_EQ(H->CalleeArgInfo, Expected.CalleeArgInfo);
EXPECT_EQ(H->CallPassType, Expected.CallPassType);
Expand Down Expand Up @@ -3448,13 +3455,14 @@ template <typename T, typename C = bool> class Foo {})",
HI.Size = 32;
HI.Offset = 96;
HI.Padding = 32;
HI.Align = 32;
},
R"(field foo
Type: type (aka can_type)
Value = value
Offset: 12 bytes
Size: 4 bytes (+4 bytes padding)
Size: 4 bytes (+4 bytes padding), alignment 4 bytes
// In test::Bar
def)",
Expand All @@ -3470,13 +3478,14 @@ def)",
HI.Size = 25;
HI.Offset = 35;
HI.Padding = 4;
HI.Align = 64;
},
R"(field foo
Type: type (aka can_type)
Value = value
Offset: 4 bytes and 3 bits
Size: 25 bits (+4 bits padding)
Size: 25 bits (+4 bits padding), alignment 8 bytes
// In test::Bar
def)",
Expand Down

0 comments on commit c300884

Please sign in to comment.