mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-01 12:43:47 +00:00
[clangd] Print qualifiers of out-of-line definitions in document outline
Summary: To improve the UX around navigating and searching through the results. Reviewers: hokein Reviewed By: hokein Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66215 llvm-svn: 368842
This commit is contained in:
parent
d81a869876
commit
38fa1a9168
@ -12,6 +12,9 @@
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
@ -96,10 +99,27 @@ std::string printQualifiedName(const NamedDecl &ND) {
|
||||
return QName;
|
||||
}
|
||||
|
||||
static bool isAnonymous(const DeclarationName &N) {
|
||||
return N.isIdentifier() && !N.getAsIdentifierInfo();
|
||||
}
|
||||
|
||||
/// Returns a nested name specifier of \p ND if it was present in the source,
|
||||
/// e.g.
|
||||
/// void ns::something::foo() -> returns 'ns::something'
|
||||
/// void foo() -> returns null
|
||||
static NestedNameSpecifier *getQualifier(const NamedDecl &ND) {
|
||||
if (auto *V = llvm::dyn_cast<DeclaratorDecl>(&ND))
|
||||
return V->getQualifier();
|
||||
if (auto *T = llvm::dyn_cast<TagDecl>(&ND))
|
||||
return T->getQualifier();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
|
||||
std::string Name;
|
||||
llvm::raw_string_ostream Out(Name);
|
||||
PrintingPolicy PP(Ctx.getLangOpts());
|
||||
|
||||
// Handle 'using namespace'. They all have the same name - <using-directive>.
|
||||
if (auto *UD = llvm::dyn_cast<UsingDirectiveDecl>(&ND)) {
|
||||
Out << "using namespace ";
|
||||
@ -108,19 +128,27 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) {
|
||||
UD->getNominatedNamespaceAsWritten()->printName(Out);
|
||||
return Out.str();
|
||||
}
|
||||
ND.getDeclName().print(Out, PP);
|
||||
if (!Out.str().empty()) {
|
||||
Out << printTemplateSpecializationArgs(ND);
|
||||
return Out.str();
|
||||
|
||||
if (isAnonymous(ND.getDeclName())) {
|
||||
// Come up with a presentation for an anonymous entity.
|
||||
if (isa<NamespaceDecl>(ND))
|
||||
return "(anonymous namespace)";
|
||||
if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
|
||||
return ("(anonymous " + Cls->getKindName() + ")").str();
|
||||
if (isa<EnumDecl>(ND))
|
||||
return "(anonymous enum)";
|
||||
return "(anonymous)";
|
||||
}
|
||||
// The name was empty, so present an anonymous entity.
|
||||
if (isa<NamespaceDecl>(ND))
|
||||
return "(anonymous namespace)";
|
||||
if (auto *Cls = llvm::dyn_cast<RecordDecl>(&ND))
|
||||
return ("(anonymous " + Cls->getKindName() + ")").str();
|
||||
if (isa<EnumDecl>(ND))
|
||||
return "(anonymous enum)";
|
||||
return "(anonymous)";
|
||||
|
||||
// Print nested name qualifier if it was written in the source code.
|
||||
if (auto *Qualifier = getQualifier(ND))
|
||||
Qualifier->print(Out, PP);
|
||||
// Print the name itself.
|
||||
ND.getDeclName().print(Out, PP);
|
||||
// Print template arguments.
|
||||
Out << printTemplateSpecializationArgs(ND);
|
||||
|
||||
return Out.str();
|
||||
}
|
||||
|
||||
std::string printTemplateSpecializationArgs(const NamedDecl &ND) {
|
||||
|
@ -19,7 +19,6 @@ namespace clangd {
|
||||
namespace {
|
||||
|
||||
using ::testing::AllOf;
|
||||
using ::testing::AnyOf;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Field;
|
||||
@ -414,21 +413,22 @@ TEST_F(DocumentSymbolsTest, BasicSymbols) {
|
||||
AllOf(WithName("KInt"), WithKind(SymbolKind::Variable), Children()),
|
||||
AllOf(WithName("kStr"), WithKind(SymbolKind::Variable), Children()),
|
||||
AllOf(WithName("f1"), WithKind(SymbolKind::Function), Children()),
|
||||
AllOf(WithName("foo"), WithKind(SymbolKind::Namespace),
|
||||
Children(
|
||||
AllOf(WithName("int32"), WithKind(SymbolKind::Class),
|
||||
Children()),
|
||||
AllOf(WithName("int32_t"), WithKind(SymbolKind::Class),
|
||||
Children()),
|
||||
AllOf(WithName("v1"), WithKind(SymbolKind::Variable),
|
||||
Children()),
|
||||
AllOf(WithName("bar"), WithKind(SymbolKind::Namespace),
|
||||
Children(AllOf(WithName("v2"),
|
||||
WithKind(SymbolKind::Variable),
|
||||
Children()))),
|
||||
AllOf(WithName("baz"), WithKind(SymbolKind::Namespace),
|
||||
Children()),
|
||||
AllOf(WithName("v2"), WithKind(SymbolKind::Namespace))))}));
|
||||
AllOf(
|
||||
WithName("foo"), WithKind(SymbolKind::Namespace),
|
||||
Children(
|
||||
AllOf(WithName("int32"), WithKind(SymbolKind::Class),
|
||||
Children()),
|
||||
AllOf(WithName("int32_t"), WithKind(SymbolKind::Class),
|
||||
Children()),
|
||||
AllOf(WithName("v1"), WithKind(SymbolKind::Variable),
|
||||
Children()),
|
||||
AllOf(WithName("bar"), WithKind(SymbolKind::Namespace),
|
||||
Children(AllOf(WithName("v2"),
|
||||
WithKind(SymbolKind::Variable),
|
||||
Children()))),
|
||||
AllOf(WithName("baz"), WithKind(SymbolKind::Namespace),
|
||||
Children()),
|
||||
AllOf(WithName("v2"), WithKind(SymbolKind::Namespace))))}));
|
||||
}
|
||||
|
||||
TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
|
||||
@ -442,13 +442,14 @@ TEST_F(DocumentSymbolsTest, DeclarationDefinition) {
|
||||
)");
|
||||
|
||||
addFile(FilePath, Main.code());
|
||||
EXPECT_THAT(getSymbols(FilePath),
|
||||
ElementsAre(AllOf(WithName("Foo"), WithKind(SymbolKind::Class),
|
||||
Children(AllOf(
|
||||
WithName("f"), WithKind(SymbolKind::Method),
|
||||
SymNameRange(Main.range("decl"))))),
|
||||
AllOf(WithName("f"), WithKind(SymbolKind::Method),
|
||||
SymNameRange(Main.range("def")))));
|
||||
EXPECT_THAT(
|
||||
getSymbols(FilePath),
|
||||
ElementsAre(
|
||||
AllOf(WithName("Foo"), WithKind(SymbolKind::Class),
|
||||
Children(AllOf(WithName("f"), WithKind(SymbolKind::Method),
|
||||
SymNameRange(Main.range("decl"))))),
|
||||
AllOf(WithName("Foo::f"), WithKind(SymbolKind::Method),
|
||||
SymNameRange(Main.range("def")))));
|
||||
}
|
||||
|
||||
TEST_F(DocumentSymbolsTest, ExternSymbol) {
|
||||
@ -684,5 +685,69 @@ TEST_F(DocumentSymbolsTest, TempSpecs) {
|
||||
AllOf(WithName("Foo<bool, int, 3>"), WithKind(SymbolKind::Class))));
|
||||
}
|
||||
|
||||
TEST_F(DocumentSymbolsTest, Qualifiers) {
|
||||
addFile("foo.cpp", R"cpp(
|
||||
namespace foo { namespace bar {
|
||||
struct Cls;
|
||||
|
||||
int func1();
|
||||
int func2();
|
||||
int func3();
|
||||
int func4();
|
||||
}}
|
||||
|
||||
struct foo::bar::Cls { };
|
||||
|
||||
int foo::bar::func1() { return 10; }
|
||||
int ::foo::bar::func2() { return 20; }
|
||||
|
||||
using namespace foo;
|
||||
int bar::func3() { return 30; }
|
||||
|
||||
namespace alias = foo::bar;
|
||||
int ::alias::func4() { return 40; }
|
||||
)cpp");
|
||||
|
||||
// All the qualifiers should be preserved exactly as written.
|
||||
EXPECT_THAT(getSymbols("foo.cpp"),
|
||||
UnorderedElementsAre(
|
||||
WithName("foo"), WithName("foo::bar::Cls"),
|
||||
WithName("foo::bar::func1"), WithName("::foo::bar::func2"),
|
||||
WithName("using namespace foo"), WithName("bar::func3"),
|
||||
WithName("alias"), WithName("::alias::func4")));
|
||||
}
|
||||
|
||||
TEST_F(DocumentSymbolsTest, QualifiersWithTemplateArgs) {
|
||||
addFile("foo.cpp", R"cpp(
|
||||
template <typename T, typename U = double> class Foo;
|
||||
|
||||
template <>
|
||||
class Foo<int, double> {
|
||||
int method1();
|
||||
int method2();
|
||||
int method3();
|
||||
};
|
||||
|
||||
using int_type = int;
|
||||
|
||||
// Typedefs should be preserved!
|
||||
int Foo<int_type, double>::method1() { return 10; }
|
||||
|
||||
// Default arguments should not be shown!
|
||||
int Foo<int>::method2() { return 20; }
|
||||
|
||||
using Foo_type = Foo<int>;
|
||||
// If the whole type is aliased, this should be preserved too!
|
||||
int Foo_type::method3() { return 30; }
|
||||
)cpp");
|
||||
EXPECT_THAT(
|
||||
getSymbols("foo.cpp"),
|
||||
UnorderedElementsAre(WithName("Foo"), WithName("Foo<int, double>"),
|
||||
WithName("int_type"),
|
||||
WithName("Foo<int_type, double>::method1"),
|
||||
WithName("Foo<int>::method2"), WithName("Foo_type"),
|
||||
WithName("Foo_type::method3")));
|
||||
}
|
||||
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
Loading…
x
Reference in New Issue
Block a user