//===--- SymbolGraph.cpp - Symbol Graph Data Structure -------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "clang/AST/DeclObjC.h" #include "swift/AST/Decl.h" #include "swift/AST/Module.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Sema/IDETypeChecking.h" #include "swift/Serialization/SerializedModuleLoader.h" #include "DeclarationFragmentPrinter.h" #include "FormatVersion.h" #include "Symbol.h" #include "SymbolGraph.h" #include "SymbolGraphASTWalker.h" using namespace swift; using namespace symbolgraphgen; SymbolGraph::SymbolGraph(SymbolGraphASTWalker &Walker, ModuleDecl &M, Optional ExtendedModule, markup::MarkupContext &Ctx, Optional ModuleVersion) : Walker(Walker), M(M), ExtendedModule(ExtendedModule), Ctx(Ctx), ModuleVersion(ModuleVersion) {} // MARK: - Utilities PrintOptions SymbolGraph::getDeclarationFragmentsPrintOptions() const { PrintOptions Opts; Opts.FunctionDefinitions = false; Opts.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::MatchSource; Opts.PrintGetSetOnRWProperties = false; Opts.PrintPropertyAccessors = false; Opts.PrintSubscriptAccessors = false; Opts.SkipUnderscoredKeywords = true; Opts.SkipAttributes = true; Opts.PrintOverrideKeyword = true; Opts.PrintImplicitAttrs = false; Opts.PrintFunctionRepresentationAttrs = PrintOptions::FunctionRepresentationMode::None; Opts.PrintUserInaccessibleAttrs = false; Opts.SkipPrivateStdlibDecls = true; Opts.SkipUnderscoredStdlibProtocols = true; Opts.ExclusiveAttrList.clear(); #define DECL_ATTR(SPELLING, CLASS, OPTIONS, CODE) Opts.ExcludeAttrList.push_back(DAK_##CLASS); #define TYPE_ATTR(X) Opts.ExcludeAttrList.push_back(TAK_##X); #include "swift/AST/Attr.def" return Opts; } bool SymbolGraph::isRequirementOrDefaultImplementation(const ValueDecl *VD) const { const auto *DC = VD->getDeclContext(); if (isa(DC) && VD->isProtocolRequirement()) { return true; } // At this point, VD is either a default implementation of a requirement // or a freestanding implementation from a protocol extension without // a corresponding requirement. auto *Proto = dyn_cast_or_null(DC->getSelfNominalTypeDecl()); if (!Proto) { return false; } /// Try to find a member of the owning protocol with the same name /// that is a requirement. auto FoundRequirementMemberNamed = [](DeclName Name, ProtocolDecl *Proto) -> bool { for (const auto *Member : Proto->lookupDirect(Name)) { if (isa(Member->getDeclContext()) && Member->isProtocolRequirement()) { return true; } } return false; }; if (FoundRequirementMemberNamed(VD->getFullName(), Proto)) { return true; } for (auto *Inherited : Proto->getInheritedProtocols()) { if (FoundRequirementMemberNamed(VD->getFullName(), Inherited)) { return true; } } // Couldn't find any requirement members of a protocol by this name. // It's not a requirement or default implementation of a requirement. return false; } // MARK: - Symbols (Nodes) void SymbolGraph::recordNode(Symbol S) { Nodes.insert(S); // Record all of the possible relationships (edges) originating // with this declaration. recordMemberRelationship(S); recordConformanceSynthesizedMemberRelationships(S); recordSuperclassSynthesizedMemberRelationships(S); recordConformanceRelationships(S); recordInheritanceRelationships(S); recordDefaultImplementationRelationships(S); recordOverrideRelationship(S); recordRequirementRelationships(S); recordOptionalRequirementRelationships(S); } // MARK: - Relationships (Edges) void SymbolGraph::recordEdge(Symbol Source, Symbol Target, RelationshipKind Kind, const ExtensionDecl *ConformanceExtension) { if (isImplicitlyPrivate(Target.getSymbolDecl())) { // Don't record relationships to privately named things because // we'll never be able to look up the target anyway. return; } Edges.insert({this, Kind, Source, Target, ConformanceExtension}); } void SymbolGraph::recordMemberRelationship(Symbol S) { const auto *DC = S.getSymbolDecl()->getDeclContext(); switch (DC->getContextKind()) { case DeclContextKind::GenericTypeDecl: case DeclContextKind::ExtensionDecl: case swift::DeclContextKind::EnumElementDecl: /* If this symbol is itself a protocol requirement, or is a default implementation of a protocol requirement, don't record a memberOf relationship. This is to allow distinguishing between requirements, default implementations of requirements, and just other things added to protocols in extensions not related to their requirements. */ if (isRequirementOrDefaultImplementation(S.getSymbolDecl())) { return; } return recordEdge(S, Symbol(this, DC->getSelfNominalTypeDecl(), nullptr), RelationshipKind::MemberOf()); case swift::DeclContextKind::AbstractClosureExpr: case swift::DeclContextKind::Initializer: case swift::DeclContextKind::TopLevelCodeDecl: case swift::DeclContextKind::SubscriptDecl: case swift::DeclContextKind::AbstractFunctionDecl: case swift::DeclContextKind::SerializedLocal: case swift::DeclContextKind::Module: case swift::DeclContextKind::FileUnit: break; } } void SymbolGraph::recordSuperclassSynthesizedMemberRelationships(Symbol S) { if (!Walker.Options.EmitSynthesizedMembers) { return; } // Via class inheritance... if (const auto *C = dyn_cast(S.getSymbolDecl())) { // Collect all superclass members up the inheritance chain. SmallPtrSet SuperClassMembers; const auto *Super = C->getSuperclassDecl(); while (Super) { for (const auto *SuperMember : Super->getMembers()) { if (const auto *SuperMemberVD = dyn_cast(SuperMember)) { SuperClassMembers.insert(SuperMemberVD); } } Super = Super->getSuperclassDecl(); } // Remove any that are overridden by this class. for (const auto *DerivedMember : C->getMembers()) { if (const auto *DerivedMemberVD = dyn_cast(DerivedMember)) { if (const auto *Overridden = DerivedMemberVD->getOverriddenDecl()) { SuperClassMembers.erase(Overridden); } } } // What remains in SuperClassMembers are inherited members that // haven't been overridden by the class. // Add a synthesized relationship. for (const auto *InheritedMember : SuperClassMembers) { if (canIncludeDeclAsNode(InheritedMember)) { Symbol Source(this, InheritedMember, C); Symbol Target(this, C, nullptr); Nodes.insert(Source); recordEdge(Source, Target, RelationshipKind::MemberOf()); } } } } void SymbolGraph::recordConformanceSynthesizedMemberRelationships(Symbol S) { if (!Walker.Options.EmitSynthesizedMembers) { return; } const auto VD = S.getSymbolDecl(); const NominalTypeDecl *OwningNominal = nullptr; if (const auto *ThisNominal = dyn_cast(VD)) { OwningNominal = ThisNominal; } else if (const auto *Extension = dyn_cast(VD)) { if (const auto *ExtendedNominal = Extension->getExtendedNominal()) { if (!ExtendedNominal->getModuleContext()->getNameStr() .equals(M.getNameStr())) { OwningNominal = ExtendedNominal; } else { return; } } else { return; } } else { return; } SynthesizedExtensionAnalyzer ExtensionAnalyzer(const_cast(OwningNominal), PrintOptions::printModuleInterface()); auto MergeGroupKind = SynthesizedExtensionAnalyzer::MergeGroupKind::All; ExtensionAnalyzer.forEachExtensionMergeGroup(MergeGroupKind, [&](ArrayRef ExtensionInfos){ for (const auto &Info : ExtensionInfos) { if (!Info.IsSynthesized) { continue; } // We are only interested in synthesized members that come from an // extension that we defined in our module. if (Info.EnablingExt && Info.EnablingExt->getModuleContext() != &M) { continue; } for (const auto ExtensionMember : Info.Ext->getMembers()) { if (const auto SynthMember = dyn_cast(ExtensionMember)) { if (SynthMember->isObjC()) { continue; } // There can be synthesized members on effectively private protocols // or things that conform to them. We don't want to include those. if (SynthMember->hasUnderscoredNaming()) { continue; } auto ExtendedSG = Walker.getModuleSymbolGraph(OwningNominal->getModuleContext()); Symbol Source(this, SynthMember, OwningNominal); Symbol Target(this, OwningNominal, nullptr); ExtendedSG->Nodes.insert(Source); ExtendedSG->recordEdge(Source, Target, RelationshipKind::MemberOf()); } } } }); } void SymbolGraph::recordInheritanceRelationships(Symbol S) { const auto VD = S.getSymbolDecl(); if (const auto *NTD = dyn_cast(VD)) { for (const auto &InheritanceLoc : NTD->getInherited()) { auto Ty = InheritanceLoc.getType(); if (!Ty) { continue; } auto *InheritedTypeDecl = dyn_cast_or_null(Ty->getAnyNominal()); if (!InheritedTypeDecl) { continue; } recordEdge(Symbol(this, VD, nullptr), Symbol(this, InheritedTypeDecl, nullptr), RelationshipKind::InheritsFrom()); } } } void SymbolGraph::recordDefaultImplementationRelationships(Symbol S) { const auto *VD = S.getSymbolDecl(); /// Claim a protocol `P`'s members as default implementation targets /// for `VD`. auto HandleProtocol = [=](const ProtocolDecl *P) { for (const auto *Member : P->getMembers()) { if (const auto *MemberVD = dyn_cast(Member)) { if (MemberVD->getFullName().compare(VD->getFullName()) == 0) { recordEdge(Symbol(this, VD, nullptr), Symbol(this, MemberVD, nullptr), RelationshipKind::DefaultImplementationOf()); } } } }; if (const auto *Extension = dyn_cast(VD->getDeclContext())) { if (const auto *ExtendedProtocol = Extension->getExtendedProtocolDecl()) { HandleProtocol(ExtendedProtocol); for (const auto *Inherited : ExtendedProtocol->getInheritedProtocols()) { HandleProtocol(Inherited); } } } } void SymbolGraph::recordRequirementRelationships(Symbol S) { const auto VD = S.getSymbolDecl(); if (const auto *Protocol = dyn_cast(VD->getDeclContext())) { if (VD->isProtocolRequirement()) { recordEdge(Symbol(this, VD, nullptr), Symbol(this, Protocol, nullptr), RelationshipKind::RequirementOf()); } } } void SymbolGraph::recordOptionalRequirementRelationships(Symbol S) { const auto VD = S.getSymbolDecl(); if (const auto *Protocol = dyn_cast(VD->getDeclContext())) { if (VD->isProtocolRequirement()) { if (const auto *ClangDecl = VD->getClangDecl()) { if (const auto *Method = dyn_cast(ClangDecl)) { if (Method->isOptional()) { recordEdge(Symbol(this, VD, nullptr), Symbol(this, Protocol, nullptr), RelationshipKind::OptionalRequirementOf()); } } } } } } void SymbolGraph::recordConformanceRelationships(Symbol S) { const auto VD = S.getSymbolDecl(); if (const auto *NTD = dyn_cast(VD)) { for (const auto *Conformance : NTD->getAllConformances()) { recordEdge(Symbol(this, VD, nullptr), Symbol(this, Conformance->getProtocol(), nullptr), RelationshipKind::ConformsTo(), dyn_cast_or_null(Conformance->getDeclContext())); } } } void SymbolGraph::recordOverrideRelationship(Symbol S) { const auto VD = S.getSymbolDecl(); if (const auto *Override = VD->getOverriddenDecl()) { recordEdge(Symbol(this, VD, nullptr), Symbol(this, Override, nullptr), RelationshipKind::Overrides()); } } // MARK: - Serialization void SymbolGraph::serialize(llvm::json::OStream &OS) { OS.object([&](){ OS.attributeObject("metadata", [&](){ { AttributeRAII FV("formatVersion", OS); llvm::VersionTuple FormatVersion(SWIFT_SYMBOLGRAPH_FORMAT_MAJOR, SWIFT_SYMBOLGRAPH_FORMAT_MINOR, SWIFT_SYMBOLGRAPH_FORMAT_PATCH); symbolgraphgen::serialize(FormatVersion, OS); } // end formatVersion: auto VersionString = version::getSwiftFullVersion(); StringRef VersionStringRef(VersionString.c_str(), VersionString.size()); OS.attribute("generator", VersionStringRef); }); // end metadata: OS.attributeObject("module", [&](){ OS.attribute("name", M.getNameStr()); AttributeRAII Platform("platform", OS); auto *MainFile = M.getFiles().front(); switch (MainFile->getKind()) { case FileUnitKind::Builtin: llvm_unreachable("Unexpected module kind: Builtin"); case FileUnitKind::DWARFModule: llvm_unreachable("Unexpected module kind: DWARFModule"); case FileUnitKind::Source: llvm_unreachable("Unexpected module kind: Source"); case FileUnitKind::Synthesized: llvm_unreachable("Unexpected module kind: Synthesized"); break; case FileUnitKind::SerializedAST: { auto SerializedAST = cast(MainFile); auto Target = llvm::Triple(SerializedAST->getTargetTriple()); symbolgraphgen::serialize(Target, OS); break; } case FileUnitKind::ClangModule: { auto ClangModule = cast(MainFile); if (const auto *Overlay = ClangModule->getOverlayModule()) { auto &OverlayMainFile = Overlay->getMainFile(FileUnitKind::SerializedAST); auto SerializedAST = cast(OverlayMainFile); auto Target = llvm::Triple(SerializedAST.getTargetTriple()); symbolgraphgen::serialize(Target, OS); } else { symbolgraphgen::serialize(Walker.Options.Target, OS); } break; } } }); if (ModuleVersion) { AttributeRAII MV("moduleVersion", OS); symbolgraphgen::serialize(*ModuleVersion, OS); } OS.attributeArray("symbols", [&](){ for (const auto S: Nodes) { S.serialize(OS); } }); OS.attributeArray("relationships", [&](){ for (const auto Relationship : Edges) { Relationship.serialize(OS); } }); }); } void SymbolGraph::serializeDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { DeclarationFragmentPrinter Printer(OS, Key); auto Options = getDeclarationFragmentsPrintOptions(); if (S.getSynthesizedBaseType()) { Options.setBaseType(S.getSynthesizedBaseType()); } S.getSymbolDecl()->print(Printer, Options); } void SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key, const Symbol &S, llvm::json::OStream &OS) { DeclarationFragmentPrinter Printer(OS, Key); if (const auto *TD = dyn_cast(S.getSymbolDecl())) { Printer.printAbridgedType(TD); } else { auto Options = getDeclarationFragmentsPrintOptions(); Options.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::ArgumentOnly; Options.VarInitializers = false; Options.PrintDefaultArgumentValue = false; Options.PrintEmptyArgumentNames = false; Options.PrintOverrideKeyword = false; if (S.getSynthesizedBaseType()) { Options.setBaseType(S.getSynthesizedBaseType()); } S.getSymbolDecl()->print(Printer, Options); } } void SymbolGraph::serializeDeclarationFragments(StringRef Key, Type T, llvm::json::OStream &OS) { DeclarationFragmentPrinter Printer(OS, Key); T->print(Printer, getDeclarationFragmentsPrintOptions()); } bool SymbolGraph::isImplicitlyPrivate(const ValueDecl *VD) const { // Don't record unconditionally private declarations if (VD->isPrivateStdlibDecl(/*treatNonBuiltinProtocolsAsPublic=*/false)) { return true; } // Don't record effectively internal declarations if specified if (Walker.Options.MinimumAccessLevel > AccessLevel::Internal && VD->hasUnderscoredNaming()) { return true; } // Symbols must meet the minimum access level to be included in the graph. if (VD->getFormalAccess() < Walker.Options.MinimumAccessLevel) { return true; } // Special cases below. auto BaseName = VD->getBaseName().userFacingName(); // ${MODULE}Version{Number,String} in ${Module}.h SmallString<32> VersionNameIdentPrefix { M.getName().str() }; VersionNameIdentPrefix.append("Version"); if (BaseName.startswith(VersionNameIdentPrefix.str())) { return true; } // Automatically mapped SIMD types auto IsGlobalSIMDType = llvm::StringSwitch(BaseName) #define MAP_SIMD_TYPE(C_TYPE, _, __) \ .Case("swift_" #C_TYPE "2", true) \ .Case("swift_" #C_TYPE "3", true) \ .Case("swift_" #C_TYPE "4", true) #include "swift/ClangImporter/SIMDMappedTypes.def" .Case("SWIFT_TYPEDEFS", true) .Case("char16_t", true) .Case("char32_t", true) .Default(false); if (IsGlobalSIMDType) { return true; } // Check up the parent chain. Anything inside a privately named // thing is also private. We could be looking at the `B` of `_A.B`. if (const auto *DC = VD->getDeclContext()) { if (const auto *Parent = DC->getAsDecl()) { if (const auto *ParentVD = dyn_cast(Parent)) { return isImplicitlyPrivate(ParentVD); } else if (const auto *Extension = dyn_cast(Parent)) { if (const auto *Nominal = Extension->getExtendedNominal()) { return isImplicitlyPrivate(Nominal); } } } } return false; } /// Returns `true` if the symbol should be included as a node in the graph. bool SymbolGraph::canIncludeDeclAsNode(const Decl *D) const { // If this decl isn't in this module, don't record it, // as it will appear elsewhere in its module's symbol graph. if (D->getModuleContext()->getName() != M.getName()) { return false; } if (D->isImplicit()) { return false; } if (!isa(D)) { return false; } return !isImplicitlyPrivate(cast(D)); }