[clang-tools-extra] 4bc085f - [clangd] Add OverridenBy Relation to index.

Utkarsh Saxena via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 17 22:11:28 PST 2020


Author: Utkarsh Saxena
Date: 2020-11-18T06:59:49+01:00
New Revision: 4bc085f5b3eda5273721fd787ffa65e2f155fc45

URL: https://github.com/llvm/llvm-project/commit/4bc085f5b3eda5273721fd787ffa65e2f155fc45
DIFF: https://github.com/llvm/llvm-project/commit/4bc085f5b3eda5273721fd787ffa65e2f155fc45.diff

LOG: [clangd] Add OverridenBy Relation to index.

This was previously explored in reviews.llvm.org/D69094.

Differential Revision: https://reviews.llvm.org/D91610

Added: 
    

Modified: 
    clang-tools-extra/clangd/index/Relation.cpp
    clang-tools-extra/clangd/index/Relation.h
    clang-tools-extra/clangd/index/Serialization.cpp
    clang-tools-extra/clangd/index/SymbolCollector.cpp
    clang-tools-extra/clangd/test/index-serialization/Inputs/sample.cpp
    clang-tools-extra/clangd/test/index-serialization/Inputs/sample.h
    clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx
    clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/index/Relation.cpp b/clang-tools-extra/clangd/index/Relation.cpp
index 6daa10a6f95e..2e5ae33939b0 100644
--- a/clang-tools-extra/clangd/index/Relation.cpp
+++ b/clang-tools-extra/clangd/index/Relation.cpp
@@ -13,6 +13,20 @@
 namespace clang {
 namespace clangd {
 
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const RelationKind R) {
+  switch (R) {
+  case RelationKind::BaseOf:
+    return OS << "BaseOf";
+  case RelationKind::OverriddenBy:
+    return OS << "OverriddenBy";
+  }
+  llvm_unreachable("Unhandled RelationKind enum.");
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Relation &R) {
+  return OS << R.Subject << " " << R.Predicate << " " << R.Object;
+}
+
 llvm::iterator_range<RelationSlab::iterator>
 RelationSlab::lookup(const SymbolID &Subject, RelationKind Predicate) const {
   auto IterPair = std::equal_range(Relations.begin(), Relations.end(),

diff  --git a/clang-tools-extra/clangd/index/Relation.h b/clang-tools-extra/clangd/index/Relation.h
index 363000019e70..b0326ac6eae0 100644
--- a/clang-tools-extra/clangd/index/Relation.h
+++ b/clang-tools-extra/clangd/index/Relation.h
@@ -21,11 +21,16 @@ namespace clangd {
 
 enum class RelationKind : uint8_t {
   BaseOf,
+  OverriddenBy,
 };
 
 /// Represents a relation between two symbols.
-/// For an example "A is a base class of B" may be represented
-/// as { Subject = A, Predicate = BaseOf, Object = B }.
+/// For an example:
+///   - "A is a base class of B" is represented as
+///     { Subject = A, Predicate = BaseOf, Object = B }.
+///   - "Derived::Foo overrides Base::Foo" is represented as
+///     { Subject = Base::Foo, Predicate = OverriddenBy, Object = Derived::Foo
+///     }.
 struct Relation {
   SymbolID Subject;
   RelationKind Predicate;
@@ -41,6 +46,8 @@ struct Relation {
            std::tie(Other.Subject, Other.Predicate, Other.Object);
   }
 };
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const RelationKind R);
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Relation &R);
 
 class RelationSlab {
 public:

diff  --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp
index 8b0ae3925a2f..5d48edf81343 100644
--- a/clang-tools-extra/clangd/index/Serialization.cpp
+++ b/clang-tools-extra/clangd/index/Serialization.cpp
@@ -443,7 +443,7 @@ readCompileCommand(Reader CmdReader, llvm::ArrayRef<llvm::StringRef> Strings) {
 // The current versioning scheme is simple - non-current versions are rejected.
 // If you make a breaking change, bump this version number to invalidate stored
 // data. Later we may want to support some backward compatibility.
-constexpr static uint32_t Version = 14;
+constexpr static uint32_t Version = 15;
 
 llvm::Expected<IndexFileIn> readRIFF(llvm::StringRef Data) {
   auto RIFF = riff::readFile(Data);

diff  --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index a7a6bd992f8b..94ab54be54b0 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -15,6 +15,7 @@
 #include "SourceCode.h"
 #include "SymbolLocation.h"
 #include "URI.h"
+#include "index/Relation.h"
 #include "index/SymbolID.h"
 #include "support/Logger.h"
 #include "clang/AST/Decl.h"
@@ -187,9 +188,12 @@ RefKind toRefKind(index::SymbolRoleSet Roles, bool Spelled = false) {
   return Result;
 }
 
-bool shouldIndexRelation(const index::SymbolRelation &R) {
-  // We currently only index BaseOf relations, for type hierarchy subtypes.
-  return R.Roles & static_cast<unsigned>(index::SymbolRole::RelationBaseOf);
+llvm::Optional<RelationKind> indexableRelation(const index::SymbolRelation &R) {
+  if (R.Roles & static_cast<unsigned>(index::SymbolRole::RelationBaseOf))
+    return RelationKind::BaseOf;
+  if (R.Roles & static_cast<unsigned>(index::SymbolRole::RelationOverrideOf))
+    return RelationKind::OverriddenBy;
+  return None;
 }
 
 } // namespace
@@ -486,14 +490,10 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,
 void SymbolCollector::processRelations(
     const NamedDecl &ND, const SymbolID &ID,
     ArrayRef<index::SymbolRelation> Relations) {
-  // Store subtype relations.
-  if (!dyn_cast<TagDecl>(&ND))
-    return;
-
   for (const auto &R : Relations) {
-    if (!shouldIndexRelation(R))
+    auto RKind = indexableRelation(R);
+    if (!RKind)
       continue;
-
     const Decl *Object = R.RelatedSymbol;
 
     auto ObjectID = getSymbolID(Object);
@@ -509,7 +509,10 @@ void SymbolCollector::processRelations(
     //       in the index and find nothing, but that's a situation they
     //       probably need to handle for other reasons anyways.
     // We currently do (B) because it's simpler.
-    this->Relations.insert(Relation{ID, RelationKind::BaseOf, ObjectID});
+    if (*RKind == RelationKind::BaseOf)
+      this->Relations.insert({ID, *RKind, ObjectID});
+    else if (*RKind == RelationKind::OverriddenBy)
+      this->Relations.insert({ObjectID, *RKind, ID});
   }
 }
 

diff  --git a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.cpp b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.cpp
index 7fe4e80f0477..f9f13b930d62 100644
--- a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.cpp
+++ b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.cpp
@@ -2,4 +2,7 @@
 #include "sample.h"
 
 // This introduces a symbol, a reference and a relation.
-struct Bar : public Foo {};
+struct Bar : public Foo {
+  // This introduces an OverriddenBy relation by implementing Foo::Func.
+  void Func() override {}
+};

diff  --git a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.h b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.h
index 7cf73b9c43ab..ef57ae7f025a 100644
--- a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.h
+++ b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.h
@@ -1,4 +1,6 @@
 #pragma once
 
 // Introduce a symbol.
-struct Foo {};
+struct Foo {
+  virtual void Func() {}
+};

diff  --git a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx
index 5ecb294f3191..11ee69bd2dd2 100644
Binary files a/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx and b/clang-tools-extra/clangd/test/index-serialization/Inputs/sample.idx 
diff er

diff  --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
index d0c4dd4497fa..93ed33eeb6b0 100644
--- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -97,6 +97,9 @@ MATCHER(RefRange, "") {
   const Range &Range = ::testing::get<1>(arg);
   return rangesMatch(Pos.Location, Range);
 }
+MATCHER_P2(OverriddenBy, Subject, Object, "") {
+  return arg == Relation{Subject.ID, RelationKind::OverriddenBy, Object.ID};
+}
 ::testing::Matcher<const std::vector<Ref> &>
 HaveRanges(const std::vector<Range> Ranges) {
   return ::testing::UnorderedPointwise(RefRange(), Ranges);
@@ -1031,7 +1034,7 @@ TEST_F(SymbolCollectorTest, RefsInHeaders) {
                                   HaveRanges(Header.ranges("macro")))));
 }
 
-TEST_F(SymbolCollectorTest, Relations) {
+TEST_F(SymbolCollectorTest, BaseOfRelations) {
   std::string Header = R"(
   class Base {};
   class Derived : public Base {};
@@ -1043,6 +1046,77 @@ TEST_F(SymbolCollectorTest, Relations) {
               Contains(Relation{Base.ID, RelationKind::BaseOf, Derived.ID}));
 }
 
+TEST_F(SymbolCollectorTest, OverrideRelationsSimpleInheritance) {
+  std::string Header = R"cpp(
+    class A {
+      virtual void foo();
+    };
+    class B : public A {
+      void foo() override;  // A::foo
+      virtual void bar();
+    };
+    class C : public B {
+      void bar() override;  // B::bar
+    };
+    class D: public C {
+      void foo() override;  // B::foo
+      void bar() override;  // C::bar
+    };
+  )cpp";
+  runSymbolCollector(Header, /*Main=*/"");
+  const Symbol &AFoo = findSymbol(Symbols, "A::foo");
+  const Symbol &BFoo = findSymbol(Symbols, "B::foo");
+  const Symbol &DFoo = findSymbol(Symbols, "D::foo");
+
+  const Symbol &BBar = findSymbol(Symbols, "B::bar");
+  const Symbol &CBar = findSymbol(Symbols, "C::bar");
+  const Symbol &DBar = findSymbol(Symbols, "D::bar");
+
+  std::vector<Relation> Result;
+  for (const Relation &R : Relations)
+    if (R.Predicate == RelationKind::OverriddenBy)
+      Result.push_back(R);
+  EXPECT_THAT(Result, UnorderedElementsAre(
+                          OverriddenBy(AFoo, BFoo), OverriddenBy(BBar, CBar),
+                          OverriddenBy(BFoo, DFoo), OverriddenBy(CBar, DBar)));
+}
+
+TEST_F(SymbolCollectorTest, OverrideRelationsMultipleInheritance) {
+  std::string Header = R"cpp(
+    class A {
+      virtual void foo();
+    };
+    class B {
+      virtual void bar();
+    };
+    class C : public B {
+      void bar() override;  // B::bar
+      virtual void baz();
+    }
+    class D : public A, C {
+      void foo() override;  // A::foo
+      void bar() override;  // C::bar
+      void baz() override;  // C::baz
+    };
+  )cpp";
+  runSymbolCollector(Header, /*Main=*/"");
+  const Symbol &AFoo = findSymbol(Symbols, "A::foo");
+  const Symbol &BBar = findSymbol(Symbols, "B::bar");
+  const Symbol &CBar = findSymbol(Symbols, "C::bar");
+  const Symbol &CBaz = findSymbol(Symbols, "C::baz");
+  const Symbol &DFoo = findSymbol(Symbols, "D::foo");
+  const Symbol &DBar = findSymbol(Symbols, "D::bar");
+  const Symbol &DBaz = findSymbol(Symbols, "D::baz");
+
+  std::vector<Relation> Result;
+  for (const Relation &R : Relations)
+    if (R.Predicate == RelationKind::OverriddenBy)
+      Result.push_back(R);
+  EXPECT_THAT(Result, UnorderedElementsAre(
+                          OverriddenBy(BBar, CBar), OverriddenBy(AFoo, DFoo),
+                          OverriddenBy(CBar, DBar), OverriddenBy(CBaz, DBaz)));
+}
+
 TEST_F(SymbolCollectorTest, CountReferences) {
   const std::string Header = R"(
     class W;


        


More information about the cfe-commits mailing list