diff --git a/clang-tools-extra/clangd/XRefs.h b/clang-tools-extra/clangd/XRefs.h --- a/clang-tools-extra/clangd/XRefs.h +++ b/clang-tools-extra/clangd/XRefs.h @@ -103,6 +103,8 @@ llvm::Optional> Parameters; /// Set for all templates(function, class, variable). llvm::Optional> TemplateParameters; + /// Contains the evaluated value of the symbol if exists. + llvm::Optional Value; /// Produce a user-readable information. FormattedString present() const; diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -719,6 +719,19 @@ VD->getType().print(OS, Policy); } + // Fill in value with evaluated initializer if possible. + if (const auto *Var = dyn_cast(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(Ctx), + Var->getType()); + } + } + } + HI.Definition = printDefinition(D); return HI; } diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -661,15 +661,16 @@ }}, // Variable with template type {R"cpp( - template class Foo {}; - Foo [[fo^o]]; + template class Foo { public: Foo(int); }; + Foo [[fo^o]] = Foo(5); )cpp", [](HoverInfo &HI) { HI.NamespaceScope = ""; HI.Name = "foo"; HI.Kind = SymbolKind::Variable; - HI.Definition = "Foo foo"; + HI.Definition = "Foo foo = Foo(5)"; HI.Type = "Foo"; + HI.Value = "Foo(5)"; }}, // Implicit template instantiation {R"cpp( @@ -786,6 +787,7 @@ {std::string("int"), std::string("T"), llvm::None}, {std::string("bool"), std::string("B"), llvm::None}, }; + HI.Value = "&b"; return HI; }}, // Lambda parameter with decltype reference @@ -850,6 +852,7 @@ {std::string("int"), std::string("T"), llvm::None}, {std::string("bool"), std::string("B"), llvm::None}, }; + HI.Value = "[&bar](int T, bool B) -> bool {}"; return HI; }}, // Local variable in lambda @@ -911,6 +914,72 @@ HI.Name = "MACRO", HI.Kind = SymbolKind::String, HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z);"; }}, + + // constexprs + {R"cpp( + int add(int a, int b) { return a + b; } + int [[b^ar]] = add(1, 2); + )cpp", + [](HoverInfo &HI) { + HI.Name = "bar"; + HI.Definition = "int bar = add(1, 2)"; + HI.Kind = SymbolKind::Variable; + HI.Type = "int"; + HI.NamespaceScope = ""; + HI.Value = "3"; + }}, + {R"cpp( + int [[b^ar]] = sizeof(char); + )cpp", + [](HoverInfo &HI) { + HI.Name = "bar"; + HI.Definition = "int bar = sizeof(char)"; + HI.Kind = SymbolKind::Variable; + HI.Type = "int"; + HI.NamespaceScope = ""; + HI.Value = "1"; + }}, + {R"cpp( + template struct Add { + static constexpr int result = a + b; + }; + int [[ba^r]] = Add<1, 2>::result; + )cpp", + [](HoverInfo &HI) { + HI.Name = "bar"; + HI.Definition = "int bar = Add<1, 2>::result"; + HI.Kind = SymbolKind::Variable; + HI.Type = "int"; + HI.NamespaceScope = ""; + HI.Value = "3"; + }}, + // FIXME: We should use TypeLoc instead of Decl to extract the concrete + // value. + {R"cpp( + template struct Add { + static constexpr int result = a + b; + }; + int bar = Add<1, 2>::[[resu^lt]]; + )cpp", + [](HoverInfo &HI) { + HI.Name = "result"; + HI.Definition = "static constexpr int result = a + b"; + HI.Kind = SymbolKind::Property; + HI.Type = "const int"; + HI.NamespaceScope = ""; + HI.LocalScope = "Add::"; + }}, + {R"cpp( + const char *[[ba^r]] = "1234"; + )cpp", + [](HoverInfo &HI) { + HI.Name = "bar"; + HI.Definition = "const char *bar = \"1234\""; + HI.Kind = SymbolKind::Variable; + HI.Type = "const char *"; + HI.NamespaceScope = ""; + HI.Value = "&\"1234\"[0]"; + }}, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Code);