diff --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h --- a/clang-tools-extra/clangd/index/SymbolCollector.h +++ b/clang-tools-extra/clangd/index/SymbolCollector.h @@ -110,6 +110,7 @@ SymbolSlab takeSymbols() { return std::move(Symbols).build(); } RefSlab takeRefs() { return std::move(Refs).build(); } + RelationSlab takeRelations() { return std::move(Relations).build(); } void finish() override; @@ -117,6 +118,8 @@ const Symbol *addDeclaration(const NamedDecl &, SymbolID, bool IsMainFileSymbol); void addDefinition(const NamedDecl &, const Symbol &DeclSymbol); + void processRelations(const NamedDecl &ND, const SymbolID &ID, + ArrayRef Relations); llvm::Optional getIncludeHeader(llvm::StringRef QName, FileID); bool isSelfContainedHeader(FileID); @@ -135,6 +138,8 @@ // Only symbols declared in preamble (from #include) and referenced from the // main file will be included. RefSlab::Builder Refs; + // All relations collected from the AST. + RelationSlab::Builder Relations; ASTContext *ASTCtx; std::shared_ptr PP; std::shared_ptr CompletionAllocator; 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 @@ -291,6 +291,12 @@ SM.getFileID(SpellingLoc) == SM.getMainFileID()) ReferencedDecls.insert(ND); + auto ID = getSymbolID(ND); + if (!ID) + return true; + + processRelations(*ND, *ID, Relations); + bool CollectRef = static_cast(Opts.RefFilter) & Roles; bool IsOnlyRef = !(Roles & (static_cast(index::SymbolRole::Declaration) | @@ -315,10 +321,6 @@ if (IsOnlyRef) return true; - auto ID = getSymbolID(ND); - if (!ID) - return true; - // FIXME: ObjCPropertyDecl are not properly indexed here: // - ObjCPropertyDecl may have an OrigD of ObjCPropertyImplDecl, which is // not a NamedDecl. @@ -338,6 +340,7 @@ if (Roles & static_cast(index::SymbolRole::Definition)) addDefinition(*OriginalDecl, *BasicSymbol); + return true; } @@ -416,8 +419,43 @@ return true; } -void SymbolCollector::setIncludeLocation(const Symbol &S, - SourceLocation Loc) { +void SymbolCollector::processRelations( + const NamedDecl &ND, const SymbolID &ID, + ArrayRef Relations) { + // Store subtype relations. + const CXXRecordDecl *RD = dyn_cast(&ND); + if (!RD) + return; + + for (const auto &R : Relations) { + if (!(R.Roles & static_cast(index::SymbolRole::RelationBaseOf))) { + continue; + } + const Decl *Parent = R.RelatedSymbol; + + if (const auto *CTSD = dyn_cast(Parent)) { + if (!CTSD->isExplicitSpecialization()) { + Parent = CTSD->getSpecializedTemplate(); + } + } + if (auto ParentID = getSymbolID(Parent)) { + // We are a subtype to each of our parents. + // TODO: There may be cases where the parent type is not indexed for some + // reason (e.g. currently we don't index explicit class template + // specializations). Those cases should probably be removed in due course, + // but for now there are two possible ways to handle it: + // (A) Avoid storing the relationship in such cases. + // (B) Store it anyways. Clients will likely lookup() the SymbolID + // 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, index::SymbolRole::RelationBaseOf, *ParentID}); + } + } +} + +void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation Loc) { if (Opts.CollectIncludePath) if (shouldCollectIncludePath(S.SymInfo.Kind)) // Use the expansion location to get the #include header since this is @@ -681,7 +719,7 @@ if (!Line.consume_front("#")) return false; Line = Line.ltrim(); - if (! Line.startswith("error")) + if (!Line.startswith("error")) return false; return Line.contains_lower("includ"); // Matches "include" or "including". } @@ -689,7 +727,7 @@ bool SymbolCollector::isDontIncludeMeHeader(llvm::StringRef Content) { llvm::StringRef Line; // Only sniff up to 100 lines or 10KB. - Content = Content.take_front(100*100); + Content = Content.take_front(100 * 100); for (unsigned I = 0; I < 100 && !Content.empty(); ++I) { std::tie(Line, Content) = Content.split('\n'); if (isIf(Line) && isErrorAboutInclude(Content.split('\n').first))