[clang-tools-extra] b447445 - [clangd] Show padding following a field on field hover.
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 30 08:53:14 PDT 2021
Author: Sam McCall
Date: 2021-06-30T17:50:59+02:00
New Revision: b447445eaa6f8ff826a7eab276c10bc6f133aeb0
URL: https://github.com/llvm/llvm-project/commit/b447445eaa6f8ff826a7eab276c10bc6f133aeb0
DIFF: https://github.com/llvm/llvm-project/commit/b447445eaa6f8ff826a7eab276c10bc6f133aeb0.diff
LOG: [clangd] Show padding following a field on field hover.
This displays as: `Size: 4 bytes (+4 padding)`
Also stop showing (byte) offset/size for bitfields. They're not
meaningful and using them to calculate padding is dangerous!
Differential Revision: https://reviews.llvm.org/D98377
Added:
Modified:
clang-tools-extra/clangd/Hover.cpp
clang-tools-extra/clangd/Hover.h
clang-tools-extra/clangd/unittests/HoverTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index 8b14777173a0..c71a8c40ce94 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -28,6 +28,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
@@ -770,10 +771,30 @@ void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) {
const auto *Record = FD->getParent();
if (Record)
Record = Record->getDefinition();
- if (Record && !Record->isInvalidDecl() && !Record->isDependentType()) {
- HI.Offset = Ctx.getFieldOffset(FD) / 8;
- if (auto Size = Ctx.getTypeSizeInCharsIfKnown(FD->getType()))
- HI.Size = Size->getQuantity();
+ if (Record && !Record->isInvalidDecl() && !Record->isDependentType() &&
+ !FD->isBitField()) {
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Record);
+ HI.Offset = Layout.getFieldOffset(FD->getFieldIndex()) / 8;
+ if (auto Size = Ctx.getTypeSizeInCharsIfKnown(FD->getType())) {
+ HI.Size = FD->isZeroSize(Ctx) ? 0 : Size->getQuantity();
+ unsigned EndOfField = *HI.Offset + *HI.Size;
+
+ // Calculate padding following the field.
+ if (!Record->isUnion() &&
+ FD->getFieldIndex() + 1 < Layout.getFieldCount()) {
+ // Measure padding up to the next class field.
+ unsigned NextOffset =
+ Layout.getFieldOffset(FD->getFieldIndex() + 1) / 8;
+ if (NextOffset >= EndOfField) // next field could be a bitfield!
+ HI.Padding = NextOffset - EndOfField;
+ } else {
+ // Measure padding up to the end of the object.
+ HI.Padding = Layout.getSize().getQuantity() - EndOfField;
+ }
+ }
+ // Offset in a union is always zero, so not really useful to report.
+ if (Record->isUnion())
+ HI.Offset.reset();
}
return;
}
@@ -1013,9 +1034,12 @@ markup::Document HoverInfo::present() const {
Output.addParagraph().appendText(
llvm::formatv("Offset: {0} byte{1}", *Offset, *Offset == 1 ? "" : "s")
.str());
- if (Size)
- Output.addParagraph().appendText(
+ if (Size) {
+ auto &P = Output.addParagraph().appendText(
llvm::formatv("Size: {0} byte{1}", *Size, *Size == 1 ? "" : "s").str());
+ if (Padding && *Padding != 0)
+ P.appendText(llvm::formatv(" (+{0} padding)", *Padding).str());
+ }
if (CalleeArgInfo) {
assert(CallPassType);
diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h
index 2f2afbf6723b..44ee9b7d7979 100644
--- a/clang-tools-extra/clangd/Hover.h
+++ b/clang-tools-extra/clangd/Hover.h
@@ -77,6 +77,8 @@ struct HoverInfo {
llvm::Optional<uint64_t> Size;
/// Contains the offset of fields within the enclosing class.
llvm::Optional<uint64_t> Offset;
+ /// Contains the padding following a field within the enclosing class.
+ llvm::Optional<uint64_t> Padding;
// Set when symbol is inside function call. Contains information extracted
// from the callee definition about the argument this is passed as.
llvm::Optional<Param> CalleeArgInfo;
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index c2645b99926c..9089a4859c14 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -68,8 +68,9 @@ TEST(Hover, Structured) {
// Field
{R"cpp(
namespace ns1 { namespace ns2 {
- struct Foo {
+ class Foo {
char [[b^ar]];
+ double y[2];
};
}}
)cpp",
@@ -82,6 +83,41 @@ TEST(Hover, Structured) {
HI.Type = "char";
HI.Offset = 0;
HI.Size = 1;
+ HI.Padding = 7;
+ HI.AccessSpecifier = "private";
+ }},
+ // Union field
+ {R"cpp(
+ union Foo {
+ char [[b^ar]];
+ double y[2];
+ };
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.LocalScope = "Foo::";
+ HI.Name = "bar";
+ HI.Kind = index::SymbolKind::Field;
+ HI.Definition = "char bar";
+ HI.Type = "char";
+ HI.Size = 1;
+ HI.Padding = 15;
+ HI.AccessSpecifier = "public";
+ }},
+ // Bitfield
+ {R"cpp(
+ struct Foo {
+ int [[^x]] : 1;
+ int y : 1;
+ };
+ )cpp",
+ [](HoverInfo &HI) {
+ HI.NamespaceScope = "";
+ HI.LocalScope = "Foo::";
+ HI.Name = "x";
+ HI.Kind = index::SymbolKind::Field;
+ HI.Definition = "int x : 1";
+ HI.Type = "int";
HI.AccessSpecifier = "public";
}},
// Local to class method.
@@ -2558,13 +2594,14 @@ template <typename T, typename C = bool> class Foo {})",
HI.Definition = "def";
HI.Size = 4;
HI.Offset = 12;
+ HI.Padding = 4;
},
R"(field foo
Type: type
Value = value
Offset: 12 bytes
-Size: 4 bytes
+Size: 4 bytes (+4 padding)
// In test::Bar
def)",
More information about the cfe-commits
mailing list