diff --git a/clang-tools-extra/clangd/index/Relation.h b/clang-tools-extra/clangd/index/Relation.h --- a/clang-tools-extra/clangd/index/Relation.h +++ b/clang-tools-extra/clangd/index/Relation.h @@ -21,6 +21,7 @@ enum class RelationKind : uint8_t { BaseOf, + OverridenBy, }; /// Represents a relation between two symbols. @@ -41,6 +42,8 @@ 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/Relation.cpp b/clang-tools-extra/clangd/index/Relation.cpp --- 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 ::OverridenBy: + return OS << "OverridenBy"; + } + 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::lookup(const SymbolID &Subject, RelationKind Predicate) const { auto IterPair = std::equal_range(Relations.begin(), Relations.end(), diff --git a/clang-tools-extra/clangd/index/Serialization.cpp b/clang-tools-extra/clangd/index/Serialization.cpp --- a/clang-tools-extra/clangd/index/Serialization.cpp +++ b/clang-tools-extra/clangd/index/Serialization.cpp @@ -31,26 +31,6 @@ } } // namespace -RelationKind symbolRoleToRelationKind(index::SymbolRole Role) { - // SymbolRole is used to record relations in the index. - // Only handle the relations we actually store currently. - // If we start storing more relations, this list can be expanded. - switch (Role) { - case index::SymbolRole::RelationBaseOf: - return RelationKind::BaseOf; - default: - llvm_unreachable("Unsupported symbol role"); - } -} - -index::SymbolRole relationKindToSymbolRole(RelationKind Kind) { - switch (Kind) { - case RelationKind::BaseOf: - return index::SymbolRole::RelationBaseOf; - } - llvm_unreachable("Invalid relation kind"); -} - namespace { // IO PRIMITIVES diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -16,6 +16,7 @@ #include "SourceCode.h" #include "SymbolLocation.h" #include "URI.h" +#include "index/Relation.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -184,7 +185,16 @@ bool shouldIndexRelation(const index::SymbolRelation &R) { // We currently only index BaseOf relations, for type hierarchy subtypes. - return R.Roles & static_cast(index::SymbolRole::RelationBaseOf); + return R.Roles & static_cast(index::SymbolRole::RelationBaseOf) || + R.Roles & static_cast(index::SymbolRole::RelationOverrideOf); +} + +llvm::Optional indexableRelation(const index::SymbolRelation &R) { + if (R.Roles & static_cast(index::SymbolRole::RelationBaseOf)) + return RelationKind::BaseOf; + if (R.Roles & static_cast(index::SymbolRole::RelationOverrideOf)) + return RelationKind::OverridenBy; + return None; } } // namespace @@ -422,14 +432,12 @@ void SymbolCollector::processRelations( const NamedDecl &ND, const SymbolID &ID, ArrayRef Relations) { - // Store subtype relations. - if (!dyn_cast(&ND)) - return; - for (const auto &R : Relations) { - if (!shouldIndexRelation(R)) + // if (!shouldIndexRelation(R)) + // continue; + auto RKind = indexableRelation(R); + if (!RKind) continue; - const Decl *Object = R.RelatedSymbol; auto ObjectID = getSymbolID(Object); @@ -445,7 +453,10 @@ // 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::OverridenBy) + this->Relations.insert({*ObjectID, *RKind, ID}); } } diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -676,6 +676,36 @@ Contains(Relation{Base.ID, RelationKind::BaseOf, Derived.ID})); } +TEST_F(SymbolCollectorTest, OverrideRelations) { + std::string Header = R"cpp( + class Base { + virtual void foo1(); + }; + class Derived1 : public Base { + void foo1() override; + virtual void foo2(); + }; + class Derived2 : public Derived1 { + void foo2() override; + }; + )cpp"; + runSymbolCollector(Header, /*Main=*/""); + const Symbol &Base = findSymbol(Symbols, "Base"); + const Symbol &Derived1 = findSymbol(Symbols, "Derived1"); + const Symbol &Derived2 = findSymbol(Symbols, "Derived2"); + const Symbol &Foo1 = findSymbol(Symbols, "Base::foo1"); + const Symbol &OverrideFoo1 = findSymbol(Symbols, "Derived1::foo1"); + const Symbol &Foo2 = findSymbol(Symbols, "Derived1::foo2"); + const Symbol &OverrideFoo2 = findSymbol(Symbols, "Derived2::foo2"); + EXPECT_THAT(Relations, + UnorderedElementsAreArray({ + Relation{Foo1.ID, RelationKind::OverridenBy, OverrideFoo1.ID}, + Relation{Foo2.ID, RelationKind::OverridenBy, OverrideFoo2.ID}, + Relation{Base.ID, RelationKind::BaseOf, Derived1.ID}, + Relation{Derived1.ID, RelationKind::BaseOf, Derived2.ID}, + })); +} + TEST_F(SymbolCollectorTest, References) { const std::string Header = R"( class W;