Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions clang-tools-extra/clangd/Hover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
Expand Down Expand Up @@ -450,19 +451,28 @@ std::optional<std::string> printExprValue(const Expr *E,
return std::nullopt;

// Show enums symbolically, not numerically like APValue::printPretty().
if (T->isEnumeralType() && Constant.Val.isInt() &&
Constant.Val.getInt().getSignificantBits() <= 64) {
// Compare to int64_t to avoid bit-width match requirements.
int64_t Val = Constant.Val.getInt().getExtValue();
for (const EnumConstantDecl *ECD : T->castAsEnumDecl()->enumerators())
if (ECD->getInitVal() == Val)
return llvm::formatv("{0} ({1})", ECD->getNameAsString(),
printHex(Constant.Val.getInt()))
.str();
if (T->isEnumeralType() && Constant.Val.isInt()) {
const llvm::APSInt &Val = Constant.Val.getInt();
if (Val.isRepresentableByInt64()) {
// Compare to int64_t to avoid bit-width match requirements.
int64_t Val = Constant.Val.getInt().getExtValue();
for (const EnumConstantDecl *ECD : T->castAsEnumDecl()->enumerators())
if (ECD->getInitVal() == Val)
return llvm::formatv("{0} ({1})", ECD->getNameAsString(),
printHex(Constant.Val.getInt()))
.str();
} else if (const auto UVal = Constant.Val.getInt().tryZExtValue()) {
for (const EnumConstantDecl *ECD : T->castAsEnumDecl()->enumerators())
if (ECD->getInitVal().getZExtValue() == *UVal)
return llvm::formatv("{0} ({1})", ECD->getNameAsString(),
printHex(Constant.Val.getInt()))
.str();
Comment on lines +464 to +469
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not confident if this is the right thing to do, still exploring this API.

} else
llvm_unreachable("Unhandled branch in enum symbolic representation");
}
// Show hex value of integers if they're at least 10 (or negative!)
if (T->isIntegralOrEnumerationType() && Constant.Val.isInt() &&
Constant.Val.getInt().getSignificantBits() <= 64 &&
Constant.Val.getInt().isRepresentableByInt64() &&
Constant.Val.getInt().uge(10))
return llvm::formatv("{0} ({1})", Constant.Val.getAsString(Ctx, T),
printHex(Constant.Val.getInt()))
Expand Down
47 changes: 47 additions & 0 deletions clang-tools-extra/clangd/unittests/HoverTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5015,6 +5015,53 @@ TEST(Hover, FunctionParameters) {
}
}

TEST(Hover, GH2381) {
Annotations Code(R"cpp(
struct Foo {
enum Bar : unsigned long long int {
A = -42ULL,
B = ~0ULL,
};
};
constexpr auto va$a^ = Foo::A;
constexpr auto vb$b^ = Foo::B;
)cpp");

TestTU TU = TestTU::withCode(Code.code());

for (const auto *Triplet :
{"--target=x86_64-pc-windows-msvc", "--target=x86_64-pc-linux-gnu"}) {
SCOPED_TRACE(Triplet);
TU.ExtraArgs.push_back(Triplet);
auto AST = TU.build();

{
auto H = getHover(AST, Code.point("a"), format::getLLVMStyle(), nullptr);

ASSERT_TRUE(H);
EXPECT_EQ(H->Name, "va");
EXPECT_EQ(H->Kind, index::SymbolKind::Variable);
EXPECT_EQ(H->NamespaceScope, "");
EXPECT_EQ(H->LocalScope, "");
EXPECT_EQ(H->Type, "const Foo::Bar");
EXPECT_EQ(H->Definition, "constexpr auto va = Foo::A");
EXPECT_EQ(H->Value, "A (0xffffffffffffffd6)");
}

{
auto H = getHover(AST, Code.point("b"), format::getLLVMStyle(), nullptr);

ASSERT_TRUE(H);
EXPECT_EQ(H->Name, "vb");
EXPECT_EQ(H->Kind, index::SymbolKind::Variable);
EXPECT_EQ(H->NamespaceScope, "");
EXPECT_EQ(H->LocalScope, "");
EXPECT_EQ(H->Type, "const Foo::Bar");
EXPECT_EQ(H->Definition, "constexpr auto vb = Foo::B");
EXPECT_EQ(H->Value, "B (0xffffffffffffffff)");
}
}
}
} // namespace
} // namespace clangd
} // namespace clang