This revision was automatically updated to reflect the committed changes. Closed by commit rG33d93c3d0b4a: [clangd] Show values of more expressions on hover (authored by sammccall).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D70359/new/ https://reviews.llvm.org/D70359 Files: clang-tools-extra/clangd/Hover.cpp 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 @@ -275,6 +275,7 @@ {std::string("int"), std::string("T"), llvm::None}, {std::string("bool"), std::string("B"), llvm::None}, }; + HI.Value = "false"; return HI; }}, // Lambda variable @@ -443,10 +444,23 @@ HI.Definition = "GREEN"; HI.Kind = SymbolKind::EnumMember; HI.Type = "enum Color"; - HI.Value = "1"; + HI.Value = "1"; // Numeric when hovering on the enumerator name. + }}, + {R"cpp( + enum Color { RED, GREEN, }; + Color x = GREEN; + Color y = [[^x]]; + )cpp", + [](HoverInfo &HI) { + HI.Name = "x"; + HI.NamespaceScope = ""; + HI.Definition = "enum Color x = GREEN"; + HI.Kind = SymbolKind::Variable; + HI.Type = "enum Color"; + HI.Value = "GREEN (1)"; // Symbolic when hovering on an expression. }}, // FIXME: We should use the Decl referenced, even if from an implicit - // instantiation. Then the scope would be Add<1, 2> and the value 3. + // instantiation. Then the scope would be Add<1, 2>. {R"cpp( template<int a, int b> struct Add { static constexpr int result = a + b; @@ -460,6 +474,21 @@ HI.Type = "const int"; HI.NamespaceScope = ""; HI.LocalScope = "Add<a, b>::"; + HI.Value = "3"; + }}, + {R"cpp( + constexpr int answer() { return 40 + 2; } + int x = [[ans^wer]](); + )cpp", + [](HoverInfo &HI) { + HI.Name = "answer"; + HI.Definition = "constexpr int answer()"; + HI.Kind = SymbolKind::Function; + HI.Type = "int ()"; + HI.ReturnType = "int"; + HI.Parameters.emplace(); + HI.NamespaceScope = ""; + HI.Value = "42"; }}, {R"cpp( const char *[[ba^r]] = "1234"; Index: clang-tools-extra/clangd/Hover.cpp =================================================================== --- clang-tools-extra/clangd/Hover.cpp +++ clang-tools-extra/clangd/Hover.cpp @@ -16,6 +16,7 @@ #include "SourceCode.h" #include "index/SymbolCollector.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/PrettyPrinter.h" @@ -239,6 +240,46 @@ // FIXME: handle variadics. } +llvm::Optional<std::string> printExprValue(const Expr *E, const ASTContext &Ctx) { + Expr::EvalResult Constant; + // Evaluating [[foo]]() as "&foo" isn't useful, and prevents us walking up + // to the enclosing call. + QualType T = E->getType(); + if (T->isFunctionType() || T->isFunctionPointerType() || + T->isFunctionReferenceType()) + return llvm::None; + // Attempt to evaluate. If expr is dependent, evaluation crashes! + if (E->isValueDependent() || !E->EvaluateAsRValue(Constant, Ctx)) + return llvm::None; + + // Show enums symbolically, not numerically like APValue::printPretty(). + if (T->isEnumeralType() && Constant.Val.getInt().getMinSignedBits() <= 64) { + // Compare to int64_t to avoid bit-width match requirements. + int64_t Val = Constant.Val.getInt().getExtValue(); + for (const EnumConstantDecl *ECD : + T->castAs<EnumType>()->getDecl()->enumerators()) + if (ECD->getInitVal() == Val) + return llvm::formatv("{0} ({1})", ECD->getNameAsString(), Val).str(); + } + return Constant.Val.getAsString(Ctx, E->getType()); +} + +llvm::Optional<std::string> printExprValue(const SelectionTree::Node *N, + const ASTContext &Ctx) { + for (; N; N = N->Parent) { + // Try to evaluate the first evaluable enclosing expression. + if (const Expr *E = N->ASTNode.get<Expr>()) { + if (auto Val = printExprValue(E, Ctx)) + return Val; + } else if (N->ASTNode.get<Decl>() || N->ASTNode.get<Stmt>()) { + // Refuse to cross certain non-exprs. (TypeLoc are OK as part of Exprs). + // This tries to ensure we're showing a value related to the cursor. + break; + } + } + return llvm::None; +} + /// Generate a \p Hover object given the declaration \p D. HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) { HoverInfo HI; @@ -282,18 +323,9 @@ } // Fill in value with evaluated initializer if possible. - // FIXME(kadircet): Also set Value field for expressions like "sizeof" and - // function calls. if (const auto *Var = dyn_cast<VarDecl>(D)) { - if (const Expr *Init = Var->getInit()) { - Expr::EvalResult Result; - if (!Init->isValueDependent() && Init->EvaluateAsRValue(Result, Ctx)) { - HI.Value.emplace(); - llvm::raw_string_ostream ValueOS(*HI.Value); - Result.Val.printPretty(ValueOS, const_cast<ASTContext &>(Ctx), - Init->getType()); - } - } + if (const Expr *Init = Var->getInit()) + HI.Value = printExprValue(Init, Ctx); } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { // Dependent enums (e.g. nested in template classes) don't have values yet. if (!ECD->getType()->isDependentType()) @@ -381,8 +413,16 @@ if (const SelectionTree::Node *N = Selection.commonAncestor()) { DeclRelationSet Rel = DeclRelation::TemplatePattern | DeclRelation::Alias; auto Decls = targetDecl(N->ASTNode, Rel); - if (!Decls.empty()) + if (!Decls.empty()) { HI = getHoverContents(Decls.front(), Index); + // Look for a close enclosing expression to show the value of. + if (!HI->Value) + HI->Value = printExprValue(N, AST.getASTContext()); + } + // FIXME: support hovers for other nodes? + // - certain expressions (sizeof etc) + // - built-in types + // - literals (esp user-defined) } }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits