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; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits