diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -43,6 +43,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include @@ -347,6 +348,19 @@ // FIXME: handle variadics. } +// Non-negative numbers are printed using min digits +// 0 => 0x0 +// 100 => 0x64 +// Negative numbers are sign-extended to 32/64 bits +// -2 => 0xfffffffe +// -2^32 => 0xfffffffeffffffff +static llvm::FormattedNumber printHex(const llvm::APSInt &V) { + uint64_t Bits = V.getExtValue(); + if (V.isNegative() && V.getMinSignedBits() <= 32) + return llvm::format_hex(uint32_t(Bits), 0); + return llvm::format_hex(Bits, 0); +} + llvm::Optional printExprValue(const Expr *E, const ASTContext &Ctx) { // InitListExpr has two forms, syntactic and semantic. They are the same thing @@ -381,8 +395,17 @@ for (const EnumConstantDecl *ECD : T->castAs()->getDecl()->enumerators()) if (ECD->getInitVal() == Val) - return llvm::formatv("{0} ({1})", ECD->getNameAsString(), Val).str(); + return llvm::formatv("{0} ({1})", ECD->getNameAsString(), + printHex(Constant.Val.getInt())) + .str(); } + // Show hex value of integers if they're at least 10 (or negative!) + if (T->isIntegralOrEnumerationType() && + Constant.Val.getInt().getMinSignedBits() <= 64 && + Constant.Val.getInt().uge(10)) + return llvm::formatv("{0} ({1})", Constant.Val.getAsString(Ctx, T), + printHex(Constant.Val.getInt())) + .str(); return Constant.Val.getAsString(Ctx, T); } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -490,30 +490,30 @@ HI.Value = "3"; }}, {R"cpp( - enum Color { RED, GREEN, }; + enum Color { RED = -123, GREEN = 5, }; Color x = [[GR^EEN]]; )cpp", [](HoverInfo &HI) { HI.Name = "GREEN"; HI.NamespaceScope = ""; HI.LocalScope = "Color::"; - HI.Definition = "GREEN"; + HI.Definition = "GREEN = 5"; HI.Kind = index::SymbolKind::EnumConstant; HI.Type = "enum Color"; - HI.Value = "1"; // Numeric when hovering on the enumerator name. + HI.Value = "5"; // Numeric on the enumerator name, no hex as small. }}, {R"cpp( - enum Color { RED, GREEN, }; - Color x = GREEN; + enum Color { RED = -123, GREEN = 5, }; + Color x = RED; Color y = [[^x]]; )cpp", [](HoverInfo &HI) { HI.Name = "x"; HI.NamespaceScope = ""; - HI.Definition = "Color x = GREEN"; + HI.Definition = "Color x = RED"; HI.Kind = index::SymbolKind::Variable; HI.Type = "enum Color"; - HI.Value = "GREEN (1)"; // Symbolic when hovering on an expression. + HI.Value = "RED (0xffffff85)"; // Symbolic on an expression. }}, {R"cpp( template struct Add { @@ -543,7 +543,7 @@ HI.ReturnType = "int"; HI.Parameters.emplace(); HI.NamespaceScope = ""; - HI.Value = "42"; + HI.Value = "42 (0x2a)"; }}, {R"cpp( const char *[[ba^r]] = "1234"; @@ -1468,12 +1468,12 @@ HI.Definition = "static int hey = 10"; HI.Documentation = "Global variable"; // FIXME: Value shouldn't be set in this case - HI.Value = "10"; + HI.Value = "10 (0xa)"; }}, { R"cpp(// Global variable in namespace namespace ns1 { - static int hey = 10; + static long long hey = -36637162602497; } void foo() { ns1::[[he^y]]++; @@ -1483,9 +1483,9 @@ HI.Name = "hey"; HI.Kind = index::SymbolKind::Variable; HI.NamespaceScope = "ns1::"; - HI.Type = "int"; - HI.Definition = "static int hey = 10"; - HI.Value = "10"; + HI.Type = "long long"; + HI.Definition = "static long long hey = -36637162602497L"; + HI.Value = "-36637162602497 (0xffffdeadbeefffff)"; // needs 64 bits }}, { R"cpp(// Field in anonymous struct