summarylogtreecommitdiffstats
path: root/inlay-hints-paddings.patch
blob: a73daedd2356d0b947b156c1325b6bcb96310719 (plain)
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
diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp
index 5c78b4ca7c04..6ad24108d68d 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/RecordLayout.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/SourceManager.h"
@@ -293,6 +294,73 @@ public:
     addTypeHint(Range, D->getReturnType(), /*Prefix=*/"-> ");
   }
 
+  bool VisitFieldDecl(FieldDecl *FD) {
+    const auto &Ctx = FD->getASTContext();
+    const auto *Record = FD->getParent();
+    if (Record)
+      Record = Record->getDefinition();
+    if (!Record || Record->isInvalidDecl() || Record->isDependentType())
+      return true;
+
+    const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Record);
+    unsigned EndOfField = Layout.getFieldOffset(FD->getFieldIndex());
+    if (FD->isBitField())
+      EndOfField += FD->isZeroSize(Ctx) ? 0 : FD->getBitWidthValue(Ctx);
+    else if (auto Size = Ctx.getTypeSizeInCharsIfKnown(FD->getType()))
+      EndOfField += FD->isZeroSize(Ctx) ? 0 : Size->getQuantity() * 8;
+    else
+      return true; // Can't get field size
+
+    // Calculate padding following the field.
+    uint64_t Padding = 0;
+    if (!Record->isUnion() &&
+        FD->getFieldIndex() + 1 < Layout.getFieldCount()) {
+      // Measure padding up to the next class field.
+      unsigned NextOffset = Layout.getFieldOffset(FD->getFieldIndex() + 1);
+      if (NextOffset >= EndOfField) // next field could be a bitfield!
+        Padding = NextOffset - EndOfField;
+    } else {
+      // Measure padding up to the end of the object.
+      Padding = (Layout.getSize().getQuantity() * 8) - EndOfField;
+    }
+
+    if (Padding) {
+      auto Bits = Padding % 8;
+      auto Bytes = Padding / 8;
+
+      std::string PadString = "+";
+      if (Bytes != 0)
+        PadString += std::to_string(Bytes) + (Bytes == 1 ? " byte" : " bytes");
+      if (Bits != 0)
+        PadString += (Bytes != 0 ? " and " : "") + std::to_string(Bits) +
+                     (Bits == 1 ? " bit" : " bits");
+      PadString += " padding";
+
+      if (Cfg.InlayHints.Enabled && Cfg.InlayHints.Designators) {
+        auto Loc = FD->getEndLoc().getLocWithOffset(1);
+        bool InvalidPos = false;
+        const char *Character =
+            Ctx.getSourceManager().getCharacterData(Loc, &InvalidPos);
+        while (!InvalidPos &&
+               (std::isblank(*Character) || std::isdigit(*Character) ||
+                std::isalpha(*Character) || *Character == '_')) {
+          Character++;
+          Loc = Loc.getLocWithOffset(1);
+        }
+        const char *Prefix = " (";
+        const char *Suffix = ")";
+        if (InvalidPos || *Character != ';') {
+          Loc = FD->getEndLoc();
+          Prefix = " /* ";
+          Suffix = " */";
+        }
+        addInlayHint(Loc, HintSide::Right, InlayHintKind::Designator, Prefix,
+                     PadString, Suffix);
+      }
+    }
+    return true;
+  }
+
   bool VisitVarDecl(VarDecl *D) {
     // Do not show hints for the aggregate in a structured binding,
     // but show hints for the individual bindings.