1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 0ec85fc24..f2cc66370 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -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->isInvalidDecl() && RD->isCompleteDefinition())
+ HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl());
return;
}
@@ -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())
@@ -1488,6 +1491,8 @@ markup::Document HoverInfo::present() const {
llvm::formatv(" (+{0} padding)", formatSize(*Padding)).str());
}
}
+ if (Align)
+ Output.addParagraph().appendText("Align: " + formatSize(*Align));
if (CalleeArgInfo) {
assert(CallPassType);
diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
index 6a6110091..fe689de44 100644
--- a/clang-tools-extra/clangd/Hover.h
+++ b/clang-tools-extra/clangd/Hover.h
@@ -100,6 +100,8 @@ struct HoverInfo {
std::optional<uint64_t> Padding;
/// Bitfield mask for current type
std::optional<uint64_t> Mask;
+ /// 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;
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 8c88cd525..c5623759a 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -92,6 +92,7 @@ TEST(Hover, Structured) {
HI.Offset = 0;
HI.Size = 8;
HI.Padding = 56;
+ HI.Align = 8;
HI.AccessSpecifier = "private";
}},
// Union field
@@ -110,6 +111,7 @@ TEST(Hover, Structured) {
HI.Type = "char";
HI.Size = 8;
HI.Padding = 120;
+ HI.Align = 8;
HI.AccessSpecifier = "public";
}},
// Bitfield
@@ -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.
@@ -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.
@@ -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(
@@ -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) {
@@ -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);
@@ -3448,6 +3455,7 @@ template <typename T, typename C = bool> class Foo {})",
HI.Size = 32;
HI.Offset = 96;
HI.Padding = 32;
+ HI.Align = 32;
},
R"(field foo
@@ -3455,6 +3463,7 @@ Type: type (aka can_type)
Value = value
Offset: 12 bytes
Size: 4 bytes (+4 bytes padding)
+Align: 4 bytes
// In test::Bar
def)",
@@ -3470,6 +3479,7 @@ def)",
HI.Size = 25;
HI.Offset = 35;
HI.Padding = 4;
+ HI.Align = 64;
},
R"(field foo
@@ -3477,6 +3487,7 @@ Type: type (aka can_type)
Value = value
Offset: 4 bytes and 3 bits
Size: 25 bits (+4 bits padding)
+Align: 8 bytes
// In test::Bar
def)",
|