https://github.com/HighCommander4 created https://github.com/llvm/llvm-project/pull/89570
Fixes https://github.com/clangd/clangd/issues/2020 >From d98c95bf213f0c6e81a46a9e37d376b855bb4867 Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Sun, 21 Apr 2024 20:30:16 -0400 Subject: [PATCH 1/2] [clangd] Show struct fields and enum members in hovers Fixes https://github.com/clangd/clangd/issues/959 --- clang-tools-extra/clangd/Hover.cpp | 2 ++ .../clangd/unittests/HoverTests.cpp | 17 ++++++++++++---- clang/include/clang/AST/PrettyPrinter.h | 10 +++++++++- clang/lib/AST/DeclPrinter.cpp | 20 ++++++++++++++++--- 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 06b949bc4a2b55..d7c433876b08bc 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -69,6 +69,8 @@ namespace { PrintingPolicy getPrintingPolicy(PrintingPolicy Base) { Base.AnonymousTagLocations = false; Base.TerseOutput = true; + // Show struct fields and enum members. + Base.PrintTagTypeContents = true; Base.PolishForDeclaration = true; Base.ConstantsAsWritten = true; Base.SuppressTemplateArgsInCXXConstructors = true; diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 35db757b9c15b5..8c19f5fb3b0ad0 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1645,7 +1645,16 @@ TEST(Hover, All) { { R"cpp(// Struct namespace ns1 { - struct MyClass {}; + struct MyClass { + // Public fields shown in hover + int field1; + int field2; + + // Methods and private fields not shown + void method(); + private: + bool private_field; + }; } // namespace ns1 int main() { ns1::[[My^Class]]* Params; @@ -1655,7 +1664,7 @@ TEST(Hover, All) { HI.Name = "MyClass"; HI.Kind = index::SymbolKind::Struct; HI.NamespaceScope = "ns1::"; - HI.Definition = "struct MyClass {}"; + HI.Definition = "struct MyClass {\n int field1;\n int field2;\n}"; }}, { R"cpp(// Class @@ -1685,7 +1694,7 @@ TEST(Hover, All) { HI.Name = "MyUnion"; HI.Kind = index::SymbolKind::Union; HI.NamespaceScope = "ns1::"; - HI.Definition = "union MyUnion {}"; + HI.Definition = "union MyUnion {\n int x;\n int y;\n}"; }}, { R"cpp(// Function definition via pointer @@ -2030,7 +2039,7 @@ TEST(Hover, All) { HI.Name = "Hello"; HI.Kind = index::SymbolKind::Enum; HI.NamespaceScope = ""; - HI.Definition = "enum Hello {}"; + HI.Definition = "enum Hello { ONE, TWO, THREE }"; HI.Documentation = "Enum declaration"; }}, { diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index da276e26049b00..6b8f1ae9143df3 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -70,7 +70,7 @@ struct PrintingPolicy { Restrict(LO.C99), Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11), UseVoidForZeroParams(!LO.CPlusPlus), SplitTemplateClosers(!LO.CPlusPlus11), TerseOutput(false), - PolishForDeclaration(false), Half(LO.Half), + PrintTagTypeContents(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), FullyQualifiedName(false), @@ -252,6 +252,14 @@ struct PrintingPolicy { LLVM_PREFERRED_TYPE(bool) unsigned TerseOutput : 1; + /// Print the contents of tag (i.e. record and enum) types, even with + /// TerseOutput=true. + /// + /// For record types (structs/classes/unions), this only prints public + /// data members. For enum types, this prints enumerators. + /// Has no effect if TerseOutput=false (which prints all members). + unsigned PrintTagTypeContents : 1; + /// When true, do certain refinement needed for producing proper declaration /// tag; such as, do not print attributes attached to the declaration. /// diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 43d221968ea3fb..3fe02fff687fe1 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Module.h" +#include "clang/Basic/Specifiers.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -464,8 +465,10 @@ void DeclPrinter::PrintConstructorInitializers(CXXConstructorDecl *CDecl, //---------------------------------------------------------------------------- void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { - if (Policy.TerseOutput) - return; + if (Policy.TerseOutput) { + if (!Policy.PrintTagTypeContents || !isa<TagDecl>(DC)) + return; + } if (Indent) Indentation += Policy.Indentation; @@ -474,6 +477,17 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) { + // Print enum members and public struct fields when + // PrintTagTypeContents=true. Only applicable when TerseOutput=true since + // otherwise all members are printed. + if (Policy.TerseOutput) { + assert(Policy.PrintTagTypeContents); + if (!(isa<EnumConstantDecl>(*D) || + (isa<FieldDecl>(*D) && + dyn_cast<FieldDecl>(*D)->getAccess() == AS_public))) + continue; + } + // Don't print ObjCIvarDecls, as they are printed when visiting the // containing ObjCInterfaceDecl. if (isa<ObjCIvarDecl>(*D)) @@ -1182,7 +1196,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { // Print the class definition // FIXME: Doesn't print access specifiers, e.g., "public:" - if (Policy.TerseOutput) { + if (Policy.TerseOutput && !Policy.PrintTagTypeContents) { Out << " {}"; } else { Out << " {\n"; >From 457545fbf74bb0c5359371f325af1a1fedb02f77 Mon Sep 17 00:00:00 2001 From: Nathan Ridge <zeratul...@hotmail.com> Date: Mon, 22 Apr 2024 02:24:14 -0400 Subject: [PATCH 2/2] [clangd] Show struct members when hovering over a typedef Fixes https://github.com/clangd/clangd/issues/2020 --- clang-tools-extra/clangd/Hover.cpp | 10 ++++++++++ .../clangd/unittests/HoverTests.cpp | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index d7c433876b08bc..598c2a68b7bf16 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -152,6 +152,16 @@ std::string printDefinition(const Decl *D, PrintingPolicy PP, std::string Definition; llvm::raw_string_ostream OS(Definition); D->print(OS, PP); + + // For a typedef to a TagDecl, also print the underlying TagDecl + if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { + if (const auto *TT = dyn_cast<TagType>( + TND->getUnderlyingType().getCanonicalType().getTypePtr())) { + OS << ";\n"; + TT->getDecl()->print(OS, PP); + } + } + OS.flush(); return Definition; } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 8c19f5fb3b0ad0..9657869b1b7641 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1666,6 +1666,20 @@ TEST(Hover, All) { HI.NamespaceScope = "ns1::"; HI.Definition = "struct MyClass {\n int field1;\n int field2;\n}"; }}, + { + R"cpp(// Typedef to struct + struct Point { int x; int y; }; + typedef Point TPoint; + [[TP^oint]] tp; + )cpp", + [](HoverInfo &HI) { + HI.Name = "TPoint"; + HI.Kind = index::SymbolKind::TypeAlias; + HI.NamespaceScope = ""; + HI.Type = "struct Point"; + HI.Definition = "typedef Point TPoint;\nstruct Point {\n int x;\n int y;\n}"; + } + }, { R"cpp(// Class namespace ns1 { @@ -1889,7 +1903,7 @@ TEST(Hover, All) { HI.Name = "Foo"; HI.Kind = index::SymbolKind::TypeAlias; HI.NamespaceScope = ""; - HI.Definition = "typedef struct Bar Foo"; + HI.Definition = "typedef struct Bar Foo;\nstruct Bar {}"; HI.Type = "struct Bar"; HI.Documentation = "Typedef with embedded definition"; }}, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits