[clang-tools-extra] r368842 - [clangd] Print qualifiers of out-of-line definitions in document outline

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 14 05:51:05 PDT 2019


Author: ibiryukov
Date: Wed Aug 14 05:51:04 2019
New Revision: 368842

URL: http://llvm.org/viewvc/llvm-project?rev=368842&view=rev
Log:
[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

Modified:
    clang-tools-extra/trunk/clangd/AST.cpp
    clang-tools-extra/trunk/clangd/unittests/FindSymbolsTests.cpp

Modified: clang-tools-extra/trunk/clangd/AST.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/AST.cpp?rev=368842&r1=368841&r2=368842&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/AST.cpp (original)
+++ clang-tools-extra/trunk/clangd/AST.cpp Wed Aug 14 05:51:04 2019
@@ -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 Nam
   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 &
     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) {

Modified: clang-tools-extra/trunk/clangd/unittests/FindSymbolsTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/FindSymbolsTests.cpp?rev=368842&r1=368841&r2=368842&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/FindSymbolsTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/FindSymbolsTests.cpp Wed Aug 14 05:51:04 2019
@@ -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, DeclarationD
     )");
 
   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




More information about the cfe-commits mailing list