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 1b1bcf78c985..36f4bc7c74d0 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
@@ -645,6 +646,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();
+ 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.
|