sammccall created this revision.
sammccall added a reviewer: kbobyrev.
Herald added subscribers: usaxena95, kadircet, arphaman.
sammccall requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang.

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!


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D98377

Files:
  clang-tools-extra/clangd/Hover.cpp
  clang-tools-extra/clangd/Hover.h
  clang-tools-extra/clangd/unittests/HoverTests.cpp

Index: clang-tools-extra/clangd/unittests/HoverTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -68,8 +68,9 @@
       // Field
       {R"cpp(
           namespace ns1 { namespace ns2 {
-            struct Foo {
+            class Foo {
               char [[b^ar]];
+              double y[2];
             };
           }}
           )cpp",
@@ -82,6 +83,42 @@
          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.Offset = 0;
+         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.
@@ -2544,13 +2581,14 @@
             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)",
Index: clang-tools-extra/clangd/Hover.h
===================================================================
--- clang-tools-extra/clangd/Hover.h
+++ clang-tools-extra/clangd/Hover.h
@@ -77,6 +77,8 @@
   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;
Index: clang-tools-extra/clangd/Hover.cpp
===================================================================
--- clang-tools-extra/clangd/Hover.cpp
+++ 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"
@@ -769,10 +770,27 @@
     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;
+        }
+      }
     }
     return;
   }
@@ -1012,9 +1030,12 @@
     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);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to