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 available. + 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,21 @@ VD->getType().print(OS, Policy); } + // 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(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,14 +661,14 @@ }}, // 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"; }}, // Implicit template instantiation @@ -911,6 +911,72 @@ HI.Name = "MACRO", HI.Kind = SymbolKind::String, HI.Definition = "#define MACRO(x, y, z) void foo(x, y, z);"; }}, + + // constexprs + {R"cpp( + constexpr 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 the Decl referenced, even if it comes from an + // implicit instantiation. + {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); @@ -938,6 +1004,7 @@ EXPECT_EQ(H->Parameters, Expected.Parameters); EXPECT_EQ(H->TemplateParameters, Expected.TemplateParameters); EXPECT_EQ(H->SymRange, Expected.SymRange); + EXPECT_EQ(H->Value, Expected.Value); } } // namespace clang