diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h --- a/clang-tools-extra/clang-doc/Generators.h +++ b/clang-tools-extra/clang-doc/Generators.h @@ -42,8 +42,6 @@ llvm::Expected> findGeneratorByName(llvm::StringRef Format); -std::string getAccess(AccessSpecifier AS); - std::string getTagType(TagTypeKind AS); } // namespace doc diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp --- a/clang-tools-extra/clang-doc/Generators.cpp +++ b/clang-tools-extra/clang-doc/Generators.cpp @@ -27,20 +27,6 @@ // Enum conversion -std::string getAccess(AccessSpecifier AS) { - switch (AS) { - case AccessSpecifier::AS_public: - return "public"; - case AccessSpecifier::AS_protected: - return "protected"; - case AccessSpecifier::AS_private: - return "private"; - case AccessSpecifier::AS_none: - return {}; - } - llvm_unreachable("Unknown AccessSpecifier"); -} - std::string getTagType(TagTypeKind AS) { switch (AS) { case TagTypeKind::TTK_Class: diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -402,7 +402,7 @@ Out.emplace_back(std::make_unique(HTMLTag::TAG_UL)); auto &ULBody = Out.back(); for (const auto &M : Members) { - std::string Access = getAccess(M.Access); + std::string Access = getAccessSpelling(M.Access).str(); if (Access != "") Access = Access + " "; auto LIBody = std::make_unique(HTMLTag::TAG_LI); @@ -679,7 +679,7 @@ Out.emplace_back(std::make_unique(HTMLTag::TAG_P)); auto &FunctionHeader = Out.back(); - std::string Access = getAccess(I.Access); + std::string Access = getAccessSpelling(I.Access).str(); if (Access != "") FunctionHeader->Children.emplace_back( std::make_unique(Access + " ")); diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp --- a/clang-tools-extra/clang-doc/MDGenerator.cpp +++ b/clang-tools-extra/clang-doc/MDGenerator.cpp @@ -157,7 +157,7 @@ First = false; } writeHeader(I.Name, 3, OS); - std::string Access = getAccess(I.Access); + std::string Access = getAccessSpelling(I.Access).str(); if (Access != "") writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name + "(" + Stream.str() + ")"), @@ -250,7 +250,7 @@ if (!I.Members.empty()) { writeHeader("Members", 2, OS); for (const auto &Member : I.Members) { - std::string Access = getAccess(Member.Access); + std::string Access = getAccessSpelling(Member.Access).str(); if (Access != "") writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS); else diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h --- a/clang-tools-extra/clangd/Hover.h +++ b/clang-tools-extra/clangd/Hover.h @@ -59,6 +59,9 @@ /// Source code containing the definition of the symbol. std::string Definition; + /// Access specifier for declarations inside class/struct/unions, empty for + /// others. + std::string AccessSpecifier; /// Pretty-printed variable type. /// Set only for variables. llvm::Optional Type; diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -468,6 +468,7 @@ HoverInfo HI; const ASTContext &Ctx = D->getASTContext(); + HI.AccessSpecifier = getAccessSpelling(D->getAccess()).str(); HI.NamespaceScope = getNamespaceScope(D); if (!HI.NamespaceScope->empty()) HI.NamespaceScope->append("::"); @@ -835,9 +836,12 @@ ScopeComment = "// In namespace " + llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n'; } + std::string DefinitionWithAccess = !AccessSpecifier.empty() + ? AccessSpecifier + ": " + Definition + : Definition; // Note that we don't print anything for global namespace, to not annoy // non-c++ projects or projects that are not making use of namespaces. - Output.addCodeBlock(ScopeComment + Definition); + Output.addCodeBlock(ScopeComment + DefinitionWithAccess); } return Output; } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -12,6 +12,7 @@ #include "TestIndex.h" #include "TestTU.h" #include "index/MemIndex.h" +#include "clang/Basic/Specifiers.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/None.h" #include "llvm/ADT/StringRef.h" @@ -79,6 +80,7 @@ HI.Type = "char"; HI.Offset = 0; HI.Size = 1; + HI.AccessSpecifier = "public"; }}, // Local to class method. {R"cpp( @@ -115,6 +117,7 @@ HI.Type = "char"; HI.Offset = 0; HI.Size = 1; + HI.AccessSpecifier = "public"; }}, // Struct definition shows size. {R"cpp( @@ -344,6 +347,7 @@ HI.Kind = index::SymbolKind::Constructor; HI.Definition = "X()"; HI.Parameters.emplace(); + HI.AccessSpecifier = "public"; }}, {"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]() [](HoverInfo &HI) { @@ -353,6 +357,7 @@ HI.Kind = index::SymbolKind::Destructor; HI.Definition = "~X()"; HI.Parameters.emplace(); + HI.AccessSpecifier = "private"; }}, {"class X { [[op^erator]] int(); };", [](HoverInfo &HI) { @@ -362,6 +367,7 @@ HI.Kind = index::SymbolKind::ConversionFunction; HI.Definition = "operator int()"; HI.Parameters.emplace(); + HI.AccessSpecifier = "private"; }}, {"class X { operator [[^X]](); };", [](HoverInfo &HI) { @@ -494,6 +500,7 @@ HI.NamespaceScope = ""; HI.LocalScope = "Add<1, 2>::"; HI.Value = "3"; + HI.AccessSpecifier = "public"; }}, {R"cpp( constexpr int answer() { return 40 + 2; } @@ -606,6 +613,7 @@ HI.Definition = "typename T = int"; HI.LocalScope = "foo::"; HI.Type = "typename"; + HI.AccessSpecifier = "public"; }}, {// TemplateTemplate Type Parameter R"cpp( @@ -618,6 +626,7 @@ HI.Definition = "template class T"; HI.LocalScope = "foo::"; HI.Type = "template class"; + HI.AccessSpecifier = "public"; }}, {// NonType Template Parameter R"cpp( @@ -630,6 +639,7 @@ HI.Definition = "int T = 5"; HI.LocalScope = "foo::"; HI.Type = "int"; + HI.AccessSpecifier = "public"; }}, {// Getter @@ -646,6 +656,7 @@ HI.Type = "float ()"; HI.ReturnType = "float"; HI.Parameters.emplace(); + HI.AccessSpecifier = "public"; }}, {// Setter R"cpp( @@ -664,6 +675,7 @@ HI.Parameters->emplace_back(); HI.Parameters->back().Type = "float"; HI.Parameters->back().Name = "v"; + HI.AccessSpecifier = "public"; }}, {// Setter (builder) R"cpp( @@ -682,6 +694,7 @@ HI.Parameters->emplace_back(); HI.Parameters->back().Type = "float"; HI.Parameters->back().Name = "v"; + HI.AccessSpecifier = "public"; }}, }; for (const auto &Case : Cases) { @@ -715,6 +728,7 @@ EXPECT_EQ(H->Value, Expected.Value); EXPECT_EQ(H->Size, Expected.Size); EXPECT_EQ(H->Offset, Expected.Offset); + EXPECT_EQ(H->AccessSpecifier, Expected.AccessSpecifier); } } @@ -1964,7 +1978,51 @@ // In test::Bar def)", }, - }; + { + [](HoverInfo &HI) { + HI.Kind = index::SymbolKind::Field; + HI.AccessSpecifier = "public"; + HI.Name = "foo"; + HI.LocalScope = "test::Bar::"; + HI.Definition = "def"; + }, + R"(field foo + +// In test::Bar +public: def)", + }, + { + [](HoverInfo &HI) { + HI.Definition = "int method()"; + HI.AccessSpecifier = "protected"; + HI.Kind = index::SymbolKind::InstanceMethod; + HI.NamespaceScope = ""; + HI.LocalScope = "cls::"; + HI.Name = "method"; + HI.Parameters.emplace(); + HI.ReturnType = "int"; + HI.Type = "int ()"; + }, + R"(instance-method method + +→ int + +// In cls +protected: int method())", + }, + { + [](HoverInfo &HI) { + HI.Kind = index::SymbolKind::Union; + HI.AccessSpecifier = "private"; + HI.Name = "foo"; + HI.NamespaceScope = "ns1::"; + HI.Definition = "union foo {}"; + }, + R"(union foo + +// In namespace ns1 +private: union foo {})", + }}; for (const auto &C : Cases) { HoverInfo HI; diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -365,6 +365,20 @@ }; llvm::StringRef getParameterABISpelling(ParameterABI kind); + + inline llvm::StringRef getAccessSpelling(AccessSpecifier AS) { + switch (AS) { + case AccessSpecifier::AS_public: + return "public"; + case AccessSpecifier::AS_protected: + return "protected"; + case AccessSpecifier::AS_private: + return "private"; + case AccessSpecifier::AS_none: + return {}; + } + llvm_unreachable("Unknown AccessSpecifier"); + } } // end namespace clang #endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -289,12 +289,10 @@ } void DeclPrinter::Print(AccessSpecifier AS) { - switch(AS) { - case AS_none: llvm_unreachable("No access specifier!"); - case AS_public: Out << "public"; break; - case AS_protected: Out << "protected"; break; - case AS_private: Out << "private"; break; - } + const auto AccessSpelling = getAccessSpelling(AS); + if (AccessSpelling.empty()) + llvm_unreachable("No access specifier!"); + Out << AccessSpelling; } void DeclPrinter::PrintConstructorInitializers(CXXConstructorDecl *CDecl, diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1,5 +1,6 @@ #include "clang/AST/JSONNodeDumper.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringSwitch.h" @@ -465,13 +466,10 @@ #undef FIELD2 std::string JSONNodeDumper::createAccessSpecifier(AccessSpecifier AS) { - switch (AS) { - case AS_none: return "none"; - case AS_private: return "private"; - case AS_protected: return "protected"; - case AS_public: return "public"; - } - llvm_unreachable("Unknown access specifier"); + const auto AccessSpelling = getAccessSpelling(AS); + if (AccessSpelling.empty()) + return "none"; + return AccessSpelling.str(); } llvm::json::Object diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -17,6 +17,7 @@ #include "clang/AST/LocInfoType.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" using namespace clang; @@ -436,19 +437,10 @@ } void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) { - switch (AS) { - case AS_none: - break; - case AS_public: - OS << "public"; - break; - case AS_protected: - OS << "protected"; - break; - case AS_private: - OS << "private"; - break; - } + const auto AccessSpelling = getAccessSpelling(AS); + if (AccessSpelling.empty()) + return; + OS << AccessSpelling; } void TextNodeDumper::dumpCleanupObject(