return static_cast<RefKind>(static_cast<unsigned>(RefKind::All) & Roles);
}
+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);
+}
+
} // namespace
SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}
SM.getFileID(SpellingLoc) == SM.getMainFileID())
ReferencedDecls.insert(ND);
+ auto ID = getSymbolID(ND);
+ if (!ID)
+ return true;
+
+ // Note: we need to process relations for all decl occurrences, including
+ // refs, because the indexing code only populates relations for specific
+ // occurrences. For example, RelationBaseOf is only populated for the
+ // occurrence inside the base-specifier.
+ processRelations(*ND, *ID, Relations);
+
bool CollectRef = static_cast<unsigned>(Opts.RefFilter) & Roles;
bool IsOnlyRef =
!(Roles & (static_cast<unsigned>(index::SymbolRole::Declaration) |
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.
if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
addDefinition(*OriginalDecl, *BasicSymbol);
+
return true;
}
return true;
}
+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))
+ continue;
+
+ const Decl *Object = R.RelatedSymbol;
+
+ auto ObjectID = getSymbolID(Object);
+ if (!ObjectID)
+ continue;
+
+ // Record the relation.
+ // TODO: There may be cases where the object decl is not indexed for some
+ // reason. Those cases should probably be removed in due course, but for
+ // now there are two possible ways to handle it:
+ // (A) Avoid storing the relation 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, *ObjectID});
+ }
+}
+
void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation Loc) {
if (Opts.CollectIncludePath)
if (shouldCollectIncludePath(S.SymInfo.Kind))
SymbolSlab takeSymbols() { return std::move(Symbols).build(); }
RefSlab takeRefs() { return std::move(Refs).build(); }
+ RelationSlab takeRelations() { return std::move(Relations).build(); }
void finish() override;
const Symbol *addDeclaration(const NamedDecl &, SymbolID,
bool IsMainFileSymbol);
void addDefinition(const NamedDecl &, const Symbol &DeclSymbol);
+ void processRelations(const NamedDecl &ND, const SymbolID &ID,
+ ArrayRef<index::SymbolRelation> Relations);
llvm::Optional<std::string> getIncludeHeader(llvm::StringRef QName, FileID);
bool isSelfContainedHeader(FileID);
// 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<Preprocessor> PP;
std::shared_ptr<GlobalCodeCompletionAllocator> CompletionAllocator;
assert(AST.hasValue());
const NamedDecl &ND =
Qualified ? findDecl(*AST, Name) : findUnqualifiedDecl(*AST, Name);
- const SourceManager& SM = AST->getSourceManager();
- bool MainFile = SM.isWrittenInMainFile(SM.getExpansionLoc(ND.getBeginLoc()));
+ const SourceManager &SM = AST->getSourceManager();
+ bool MainFile =
+ SM.isWrittenInMainFile(SM.getExpansionLoc(ND.getBeginLoc()));
return SymbolCollector::shouldCollectSymbol(
ND, AST->getASTContext(), SymbolCollector::Options(), MainFile);
}
Args, Factory->create(), Files.get(),
std::make_shared<PCHContainerOperations>());
- InMemoryFileSystem->addFile(
- TestHeaderName, 0, llvm::MemoryBuffer::getMemBuffer(HeaderCode));
+ InMemoryFileSystem->addFile(TestHeaderName, 0,
+ llvm::MemoryBuffer::getMemBuffer(HeaderCode));
InMemoryFileSystem->addFile(TestFileName, 0,
llvm::MemoryBuffer::getMemBuffer(MainCode));
Invocation.run();
Symbols = Factory->Collector->takeSymbols();
Refs = Factory->Collector->takeRefs();
+ Relations = Factory->Collector->takeRelations();
return true;
}
std::string TestFileURI;
SymbolSlab Symbols;
RefSlab Refs;
+ RelationSlab Relations;
SymbolCollector::Options CollectorOpts;
std::unique_ptr<CommentHandler> PragmaHandler;
};
HaveRanges(Header.ranges()))));
}
+TEST_F(SymbolCollectorTest, Relations) {
+ std::string Header = R"(
+ class Base {};
+ class Derived : public Base {};
+ )";
+ runSymbolCollector(Header, /*Main=*/"");
+ const Symbol &Base = findSymbol(Symbols, "Base");
+ const Symbol &Derived = findSymbol(Symbols, "Derived");
+ EXPECT_THAT(Relations,
+ Contains(Relation{Base.ID, index::SymbolRole::RelationBaseOf,
+ Derived.ID}));
+}
+
TEST_F(SymbolCollectorTest, References) {
const std::string Header = R"(
class W;
void f1() {}
)";
runSymbolCollector(/*Header=*/"", Main);
- EXPECT_THAT(Symbols,
- UnorderedElementsAre(QName("Foo"), QName("f1"), QName("f2"),
- QName("ff"), QName("foo"), QName("foo::Bar"),
- QName("main_f")));
+ EXPECT_THAT(Symbols, UnorderedElementsAre(
+ QName("Foo"), QName("f1"), QName("f2"), QName("ff"),
+ QName("foo"), QName("foo::Bar"), QName("main_f")));
}
TEST_F(SymbolCollectorTest, Documentation) {