diff --git a/include/swift/IDE/DigesterEnums.def b/include/swift/IDE/DigesterEnums.def index 296da03a00c..84476024c54 100644 --- a/include/swift/IDE/DigesterEnums.def +++ b/include/swift/IDE/DigesterEnums.def @@ -55,6 +55,8 @@ #endif NODE_KIND(Root, Root) +NODE_KIND(Conformance, Conformance) +NODE_KIND(TypeWitness, TypeWitness) NODE_KIND(TypeNominal, TypeNominal) NODE_KIND(TypeFunc, TypeFunc) NODE_KIND(TypeAlias, TypeNameAlias) @@ -146,12 +148,12 @@ KEY_STRING(FuncSelfKind, funcSelfKind) KEY_STRING(ParamValueOwnership, paramValueOwnership) KEY_STRING_ARR(SuperclassNames, superclassNames) -KEY_STRING_ARR(ConformingProtocols, conformingProtocols) KEY_UINT(SelfIndex, selfIndex) KEY_UINT(FixedBinaryOrder, fixedbinaryorder) KEY(children) +KEY(conformances) KEY(typeAttributes) KEY(declAttributes) KEY(declKind) diff --git a/test/api-digester/Inputs/cake.swift b/test/api-digester/Inputs/cake.swift index 888223e91a9..e09ed4679ec 100644 --- a/test/api-digester/Inputs/cake.swift +++ b/test/api-digester/Inputs/cake.swift @@ -2,7 +2,7 @@ public protocol P1 {} public protocol P2 {} - +public protocol P3: P2, P1 {} @_fixed_layout public struct S1: P1 { public static func foo1() {} diff --git a/test/api-digester/Outputs/Cake-abi.txt b/test/api-digester/Outputs/Cake-abi.txt index 8aa24b42889..0c1030c1d1e 100644 --- a/test/api-digester/Outputs/Cake-abi.txt +++ b/test/api-digester/Outputs/Cake-abi.txt @@ -72,9 +72,9 @@ cake2: Var fixedLayoutStruct.lazy_d.storage is added to a non-resilient type /* Conformance changes */ cake1: Func ObjCProtocol.addOptional() is now an optional requirement cake1: Func ObjCProtocol.removeOptional() is no longer an optional requirement -cake1: Protocol P3 has added inherited protocol P4 cake1: Protocol P3 has removed inherited protocol P2 cake1: Struct fixedLayoutStruct has removed conformance to P1 +cake2: Protocol P3 has added inherited protocol P4 /* Protocol Requirement Change */ cake1: AssociatedType AssociatedTypePro.T1 has removed default type Int diff --git a/test/api-digester/Outputs/Cake.txt b/test/api-digester/Outputs/Cake.txt index 888ae3a4862..3022d025322 100644 --- a/test/api-digester/Outputs/Cake.txt +++ b/test/api-digester/Outputs/Cake.txt @@ -45,9 +45,9 @@ cake1: Var C1.CIIns2 changes from strong to weak /* Conformance changes */ cake1: Func ObjCProtocol.removeOptional() is no longer an optional requirement -cake1: Protocol P3 has added inherited protocol P4 cake1: Protocol P3 has removed inherited protocol P2 cake1: Struct fixedLayoutStruct has removed conformance to P1 +cake2: Protocol P3 has added inherited protocol P4 /* Protocol Requirement Change */ cake1: AssociatedType AssociatedTypePro.T1 has removed default type Int diff --git a/test/api-digester/Outputs/cake-abi.json b/test/api-digester/Outputs/cake-abi.json index 5f4368f51eb..7f03b46481a 100644 --- a/test/api-digester/Outputs/cake-abi.json +++ b/test/api-digester/Outputs/cake-abi.json @@ -52,6 +52,27 @@ "usr": "s:4cake2P2P", "moduleName": "cake" }, + { + "kind": "TypeDecl", + "name": "P3", + "printedName": "P3", + "declKind": "Protocol", + "usr": "s:4cake2P3P", + "moduleName": "cake", + "genericSig": "<τ_0_0 : P1, τ_0_0 : P2>", + "conformances": [ + { + "kind": "Conformance", + "name": "P2", + "printedName": "P2" + }, + { + "kind": "Conformance", + "name": "P1", + "printedName": "P1" + } + ] + }, { "kind": "TypeDecl", "name": "S1", @@ -131,9 +152,17 @@ "declAttributes": [ "FixedLayout" ], - "conformingProtocols": [ - "P1", - "P2" + "conformances": [ + { + "kind": "Conformance", + "name": "P1", + "printedName": "P1" + }, + { + "kind": "Conformance", + "name": "P2", + "printedName": "P2" + } ] }, { @@ -652,10 +681,37 @@ "usr": "s:4cake6NumberO", "moduleName": "cake", "enumRawTypeName": "Int", - "conformingProtocols": [ - "Equatable", - "Hashable", - "RawRepresentable" + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable" + }, + { + "kind": "Conformance", + "name": "RawRepresentable", + "printedName": "RawRepresentable", + "children": [ + { + "kind": "TypeWitness", + "name": "RawValue", + "printedName": "RawValue", + "children": [ + { + "kind": "TypeNominal", + "name": "Int", + "printedName": "Int", + "usr": "s:Si" + } + ] + } + ] + } ] }, { @@ -1182,8 +1238,12 @@ "usr": "s:4cake4PSubP", "moduleName": "cake", "genericSig": "<τ_0_0 : PSuper>", - "conformingProtocols": [ - "PSuper" + "conformances": [ + { + "kind": "Conformance", + "name": "PSuper", + "printedName": "PSuper" + } ] }, { @@ -1336,28 +1396,172 @@ "declAttributes": [ "FixedLayout" ], - "conformingProtocols": [ - "Comparable", - "SignedInteger", - "_ExpressibleByBuiltinIntegerLiteral", - "BinaryInteger", - "LosslessStringConvertible", - "SignedNumeric", - "Numeric", - "CustomStringConvertible", - "Strideable", - "ExpressibleByIntegerLiteral", - "FixedWidthInteger", - "P1", - "Encodable", - "Decodable", - "Hashable", - "Equatable", - "_HasCustomAnyHashableRepresentation", - "CustomReflectable", - "_CustomPlaygroundQuickLookable", - "MirrorPath", - "CVarArg" + "conformances": [ + { + "kind": "Conformance", + "name": "Comparable", + "printedName": "Comparable" + }, + { + "kind": "Conformance", + "name": "SignedInteger", + "printedName": "SignedInteger" + }, + { + "kind": "Conformance", + "name": "_ExpressibleByBuiltinIntegerLiteral", + "printedName": "_ExpressibleByBuiltinIntegerLiteral" + }, + { + "kind": "Conformance", + "name": "BinaryInteger", + "printedName": "BinaryInteger", + "children": [ + { + "kind": "TypeWitness", + "name": "Words", + "printedName": "Words", + "children": [ + { + "kind": "TypeNominal", + "name": "Words", + "printedName": "Int.Words", + "usr": "s:Si5WordsV" + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "LosslessStringConvertible", + "printedName": "LosslessStringConvertible" + }, + { + "kind": "Conformance", + "name": "SignedNumeric", + "printedName": "SignedNumeric" + }, + { + "kind": "Conformance", + "name": "Numeric", + "printedName": "Numeric", + "children": [ + { + "kind": "TypeWitness", + "name": "Magnitude", + "printedName": "Magnitude", + "children": [ + { + "kind": "TypeNominal", + "name": "UInt", + "printedName": "UInt", + "usr": "s:Su" + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible" + }, + { + "kind": "Conformance", + "name": "Strideable", + "printedName": "Strideable", + "children": [ + { + "kind": "TypeWitness", + "name": "Stride", + "printedName": "Stride", + "children": [ + { + "kind": "TypeNominal", + "name": "Int", + "printedName": "Int", + "usr": "s:Si" + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "ExpressibleByIntegerLiteral", + "printedName": "ExpressibleByIntegerLiteral", + "children": [ + { + "kind": "TypeWitness", + "name": "IntegerLiteralType", + "printedName": "IntegerLiteralType", + "children": [ + { + "kind": "TypeNominal", + "name": "Int", + "printedName": "Int", + "usr": "s:Si" + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "FixedWidthInteger", + "printedName": "FixedWidthInteger" + }, + { + "kind": "Conformance", + "name": "P1", + "printedName": "P1" + }, + { + "kind": "Conformance", + "name": "Encodable", + "printedName": "Encodable" + }, + { + "kind": "Conformance", + "name": "Decodable", + "printedName": "Decodable" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable" + }, + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable" + }, + { + "kind": "Conformance", + "name": "_HasCustomAnyHashableRepresentation", + "printedName": "_HasCustomAnyHashableRepresentation" + }, + { + "kind": "Conformance", + "name": "CustomReflectable", + "printedName": "CustomReflectable" + }, + { + "kind": "Conformance", + "name": "_CustomPlaygroundQuickLookable", + "printedName": "_CustomPlaygroundQuickLookable" + }, + { + "kind": "Conformance", + "name": "MirrorPath", + "printedName": "MirrorPath" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg" + } ] } ] diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json index d6233157158..4fdd37acd9e 100644 --- a/test/api-digester/Outputs/cake.json +++ b/test/api-digester/Outputs/cake.json @@ -52,6 +52,27 @@ "usr": "s:4cake2P2P", "moduleName": "cake" }, + { + "kind": "TypeDecl", + "name": "P3", + "printedName": "P3", + "declKind": "Protocol", + "usr": "s:4cake2P3P", + "moduleName": "cake", + "genericSig": "", + "conformances": [ + { + "kind": "Conformance", + "name": "P2", + "printedName": "P2" + }, + { + "kind": "Conformance", + "name": "P1", + "printedName": "P1" + } + ] + }, { "kind": "TypeDecl", "name": "S1", @@ -138,9 +159,17 @@ "declAttributes": [ "FixedLayout" ], - "conformingProtocols": [ - "P1", - "P2" + "conformances": [ + { + "kind": "Conformance", + "name": "P1", + "printedName": "P1" + }, + { + "kind": "Conformance", + "name": "P2", + "printedName": "P2" + } ] }, { @@ -716,10 +745,37 @@ "usr": "s:4cake6NumberO", "moduleName": "cake", "enumRawTypeName": "Int", - "conformingProtocols": [ - "Equatable", - "Hashable", - "RawRepresentable" + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable" + }, + { + "kind": "Conformance", + "name": "RawRepresentable", + "printedName": "RawRepresentable", + "children": [ + { + "kind": "TypeWitness", + "name": "RawValue", + "printedName": "RawValue", + "children": [ + { + "kind": "TypeNominal", + "name": "Int", + "printedName": "Int", + "usr": "s:Si" + } + ] + } + ] + } ] }, { @@ -1131,8 +1187,12 @@ "usr": "s:4cake4PSubP", "moduleName": "cake", "genericSig": "", - "conformingProtocols": [ - "PSuper" + "conformances": [ + { + "kind": "Conformance", + "name": "PSuper", + "printedName": "PSuper" + } ] }, { @@ -1210,25 +1270,171 @@ "declAttributes": [ "FixedLayout" ], - "conformingProtocols": [ - "Comparable", - "SignedInteger", - "BinaryInteger", - "LosslessStringConvertible", - "SignedNumeric", - "Numeric", - "CustomStringConvertible", - "Strideable", - "ExpressibleByIntegerLiteral", - "FixedWidthInteger", - "P1", - "Encodable", - "Decodable", - "Hashable", - "Equatable", - "CustomReflectable", - "MirrorPath", - "CVarArg" + "conformances": [ + { + "kind": "Conformance", + "name": "Comparable", + "printedName": "Comparable" + }, + { + "kind": "Conformance", + "name": "SignedInteger", + "printedName": "SignedInteger" + }, + { + "kind": "Conformance", + "name": "BinaryInteger", + "printedName": "BinaryInteger", + "children": [ + { + "kind": "TypeWitness", + "name": "Words", + "printedName": "Words", + "children": [ + { + "kind": "TypeNominal", + "name": "Words", + "printedName": "Int.Words", + "usr": "s:Si5WordsV" + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "LosslessStringConvertible", + "printedName": "LosslessStringConvertible" + }, + { + "kind": "Conformance", + "name": "SignedNumeric", + "printedName": "SignedNumeric" + }, + { + "kind": "Conformance", + "name": "Numeric", + "printedName": "Numeric", + "children": [ + { + "kind": "TypeWitness", + "name": "Magnitude", + "printedName": "Magnitude", + "children": [ + { + "kind": "TypeNameAlias", + "name": "Magnitude", + "printedName": "Int.Magnitude", + "children": [ + { + "kind": "TypeNominal", + "name": "UInt", + "printedName": "UInt", + "usr": "s:Su" + } + ] + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible" + }, + { + "kind": "Conformance", + "name": "Strideable", + "printedName": "Strideable", + "children": [ + { + "kind": "TypeWitness", + "name": "Stride", + "printedName": "Stride", + "children": [ + { + "kind": "TypeNominal", + "name": "Int", + "printedName": "Int", + "usr": "s:Si" + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "ExpressibleByIntegerLiteral", + "printedName": "ExpressibleByIntegerLiteral", + "children": [ + { + "kind": "TypeWitness", + "name": "IntegerLiteralType", + "printedName": "IntegerLiteralType", + "children": [ + { + "kind": "TypeNameAlias", + "name": "IntegerLiteralType", + "printedName": "Int.IntegerLiteralType", + "children": [ + { + "kind": "TypeNominal", + "name": "Int", + "printedName": "Int", + "usr": "s:Si" + } + ] + } + ] + } + ] + }, + { + "kind": "Conformance", + "name": "FixedWidthInteger", + "printedName": "FixedWidthInteger" + }, + { + "kind": "Conformance", + "name": "P1", + "printedName": "P1" + }, + { + "kind": "Conformance", + "name": "Encodable", + "printedName": "Encodable" + }, + { + "kind": "Conformance", + "name": "Decodable", + "printedName": "Decodable" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable" + }, + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable" + }, + { + "kind": "Conformance", + "name": "CustomReflectable", + "printedName": "CustomReflectable" + }, + { + "kind": "Conformance", + "name": "MirrorPath", + "printedName": "MirrorPath" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg" + } ] } ] diff --git a/test/api-digester/Outputs/clang-module-dump.txt b/test/api-digester/Outputs/clang-module-dump.txt index 947d96b4efa..7a2435f6345 100644 --- a/test/api-digester/Outputs/clang-module-dump.txt +++ b/test/api-digester/Outputs/clang-module-dump.txt @@ -69,9 +69,17 @@ "superclassNames": [ "NSObject" ], - "conformingProtocols": [ - "ObjcProt", - "NSObjectProtocol" + "conformances": [ + { + "kind": "Conformance", + "name": "ObjcProt", + "printedName": "ObjcProt" + }, + { + "kind": "Conformance", + "name": "NSObjectProtocol", + "printedName": "NSObjectProtocol" + } ] }, { diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index d5391c49697..18218bd82d6 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -42,6 +42,7 @@ struct swift::ide::api::SDKNodeInitInfo { SDKNodeInitInfo(SDKContext &Ctx, Decl *D); SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD); SDKNodeInitInfo(SDKContext &Ctx, OperatorDecl *D); + SDKNodeInitInfo(SDKContext &Ctx, ProtocolConformance *Conform); SDKNodeInitInfo(SDKContext &Ctx, Type Ty, TypeInitInfo Info = TypeInitInfo()); SDKNode* createSDKNode(SDKNodeKind Kind); }; @@ -105,9 +106,14 @@ SDKNodeTypeAlias::SDKNodeTypeAlias(SDKNodeInitInfo Info): SDKNodeDeclType::SDKNodeDeclType(SDKNodeInitInfo Info): SDKNodeDecl(Info, SDKNodeKind::DeclType), SuperclassUsr(Info.SuperclassUsr), SuperclassNames(Info.SuperclassNames), - ConformingProtocols(Info.ConformingProtocols), EnumRawTypeName(Info.EnumRawTypeName) {} +SDKNodeConformance::SDKNodeConformance(SDKNodeInitInfo Info): + SDKNode(Info, SDKNodeKind::Conformance) {} + +SDKNodeTypeWitness::SDKNodeTypeWitness(SDKNodeInitInfo Info): + SDKNode(Info, SDKNodeKind::TypeWitness) {} + SDKNodeDeclOperator::SDKNodeDeclOperator(SDKNodeInitInfo Info): SDKNodeDecl(Info, SDKNodeKind::DeclOperator) {} @@ -217,10 +223,6 @@ void SDKNode::addChild(SDKNode *Child) { } } -ArrayRef SDKNode::getChildren() const { - return llvm::makeArrayRef(Children); -} - NodePtr SDKNode::childAt(unsigned I) const { assert(I < getChildrenCount()); return getChildren()[I]; @@ -332,6 +334,8 @@ StringRef SDKNodeType::getTypeRoleDescription() const { case SDKNodeKind::TypeAlias: case SDKNodeKind::DeclType: case SDKNodeKind::DeclOperator: + case SDKNodeKind::Conformance: + case SDKNodeKind::TypeWitness: llvm_unreachable("Type Parent is wrong"); case SDKNodeKind::DeclFunction: case SDKNodeKind::DeclConstructor: @@ -427,6 +431,15 @@ SDKNodeDecl *SDKNodeType::getClosestParentDecl() const { return Result->getAs(); } +void SDKNodeDeclType::addConformance(SDKNode *Conf) { + cast(Conf)->TypeDecl = this; + Conformances.push_back(Conf); +} + +SDKNodeType *SDKNodeTypeWitness::getUnderlyingType() const { + return getOnlyChild()->getAs(); +} + Optional SDKNodeDeclType::getSuperclass() const { if (SuperclassUsr.empty()) return None; @@ -465,9 +478,9 @@ bool SDKNodeDeclType::isConformingTo(KnownProtocolKind Kind) const { switch (Kind) { #define KNOWN_PROTOCOL(NAME) \ case KnownProtocolKind::NAME: \ - return std::find(ConformingProtocols.begin(), \ - ConformingProtocols.end(), \ - #NAME) != ConformingProtocols.end(); + return std::find_if(Conformances.begin(), Conformances.end(), \ + [](SDKNode *Conf) { return Conf->getName() == #NAME; }) != \ + Conformances.end(); #include "swift/IDE/DigesterEnums.def" } } @@ -524,6 +537,7 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx, SDKNodeKind Kind; SDKNodeInitInfo Info(Ctx); NodeVector Children; + NodeVector Conformances; for (auto &Pair : *Node) { auto keyString = GetScalarString(Pair.getKey()); @@ -551,6 +565,12 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx, cast(&Mapping))); } break; + case KeyKind::KK_conformances: + for (auto &Mapping : *cast(Pair.getValue())) { + Conformances.push_back(constructSDKNode(Ctx, + cast(&Mapping))); + } + break; #define KEY_STRING_ARR(X, Y) \ case KeyKind::KK_##Y: \ assert(Info.X.empty()); \ @@ -622,6 +642,9 @@ SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx, for (auto C : Children) { Result->addChild(C); } + for (auto *Conf: Conformances) { + cast(Result)->addConformance(Conf); + } return Result; } @@ -635,22 +658,36 @@ bool SDKNode::hasSameChildren(const SDKNode &Other) const { return true; } -void swift::ide::api::stringSetDifference(ArrayRef Left, - ArrayRef Right, - std::vector &LeftMinusRight, - std::vector &RightMinusLeft) { - std::set LS(Left.begin(), Left.end()); - std::set RS(Right.begin(), Right.end()); - std::set_difference(LS.begin(), LS.end(), RS.begin(), RS.end(), - std::back_inserter(LeftMinusRight)); - std::set_difference(RS.begin(), RS.end(), LS.begin(), LS.end(), - std::back_inserter(RightMinusLeft)); +void swift::ide::api::nodeSetDifference(ArrayRef Left, + ArrayRef Right, + NodeVector &LeftMinusRight, + NodeVector &RightMinusLeft) { + llvm::SmallPtrSet LeftToRemove; + llvm::SmallPtrSet RightToRemove; + for (auto LC: Left) { + for (auto RC: Right) { + if (!RightToRemove.count(RC) && *LC == *RC) { + LeftToRemove.insert(LC); + RightToRemove.insert(RC); + break; + } + } + } + std::for_each(Left.begin(), Left.end(), [&] (SDKNode *N) { + if (!LeftToRemove.count(N)) + LeftMinusRight.push_back(N); + }); + std::for_each(Right.begin(), Right.end(), [&] (SDKNode *N) { + if (!RightToRemove.count(N)) + RightMinusLeft.push_back(N); + }); } -static bool hasSameContents(ArrayRef Left, - ArrayRef Right) { - std::vector LeftMinusRight, RightMinusLeft; - stringSetDifference(Left, Right, LeftMinusRight, RightMinusLeft); + +static bool hasSameContents(ArrayRef Left, + ArrayRef Right) { + NodeVector LeftMinusRight, RightMinusLeft; + nodeSetDifference(Left, Right, LeftMinusRight, RightMinusLeft); return LeftMinusRight.empty() && RightMinusLeft.empty(); } @@ -736,7 +773,7 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R) auto *Left = dyn_cast(&L); auto *Right = dyn_cast(&R); if (Left && Right) { - if (!hasSameContents(Left->getAllProtocols(), Right->getAllProtocols())) { + if (!hasSameContents(Left->getConformances(), Right->getConformances())) { return false; } if (Left->getSuperClassName() != Right->getSuperClassName()) { @@ -782,6 +819,8 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R) } LLVM_FALLTHROUGH; } + case SDKNodeKind::Conformance: + case SDKNodeKind::TypeWitness: case SDKNodeKind::Root: { return L.getPrintedName() == R.getPrintedName() && L.hasSameChildren(R); @@ -1128,15 +1167,6 @@ SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) } #undef CASE - // Get all protocol names this type decl conforms to. - if (auto *NTD = dyn_cast(VD)) { - for (auto *P: NTD->getAllProtocols()) { - if (!Ctx.shouldIgnore(P)) { - ConformingProtocols.push_back(P->getName().str()); - } - } - } - // Get enum raw type name if this is an enum. if (auto *ED = dyn_cast(VD)) { if (auto RT = ED->getRawType()) { @@ -1331,6 +1361,7 @@ SDKContext::shouldIgnore(Decl *D, const Decl* Parent) const { SDKNode *swift::ide::api:: SwiftDeclCollector::constructTypeDeclNode(NominalTypeDecl *NTD) { auto TypeNode = SDKNodeInitInfo(Ctx, NTD).createSDKNode(SDKNodeKind::DeclType); + addConformancesToTypeDecl(cast(TypeNode), NTD); addMembersToRoot(TypeNode, NTD); for (auto Ext : NTD->getExtensions()) { HandledExtensions.insert(Ext); @@ -1348,7 +1379,7 @@ SDKNode *swift::ide::api:: SwiftDeclCollector::constructExternalExtensionNode(NominalTypeDecl *NTD, ArrayRef AllExts) { auto *TypeNode = SDKNodeInitInfo(Ctx, NTD).createSDKNode(SDKNodeKind::DeclType); - + addConformancesToTypeDecl(cast(TypeNode), NTD); // The members of the extensions are the only members of this synthesized type. for (auto *Ext: AllExts) { HandledExtensions.insert(Ext); @@ -1432,6 +1463,37 @@ SwiftDeclCollector::addMembersToRoot(SDKNode *Root, IterableDeclContext *Context } } +SDKNode *swift::ide::api:: +SwiftDeclCollector::constructTypeWitnessNode(AssociatedTypeDecl *Assoc, + Type Ty) { + auto *Witness = SDKNodeInitInfo(Ctx, Assoc).createSDKNode(SDKNodeKind::TypeWitness); + Witness->addChild(constructTypeNode(Ty)); + return Witness; +} + +SDKNode *swift::ide::api:: +SwiftDeclCollector::constructConformanceNode(ProtocolConformance *Conform) { + if (Ctx.checkingABI()) + Conform = Conform->getCanonicalConformance(); + auto ConfNode = cast(SDKNodeInitInfo(Ctx, + Conform->getProtocol()).createSDKNode(SDKNodeKind::Conformance)); + Conform->forEachTypeWitness(nullptr, + [&](AssociatedTypeDecl *assoc, Type ty, TypeDecl *typeDecl) -> bool { + ConfNode->addChild(constructTypeWitnessNode(assoc, ty)); + return false; + }); + return ConfNode; +} + +void swift::ide::api:: +SwiftDeclCollector::addConformancesToTypeDecl(SDKNodeDeclType *Root, + NominalTypeDecl *NTD) { + for (auto &Conf: NTD->getAllConformances()) { + if (!Ctx.shouldIgnore(Conf->getProtocol())) + Root->addConformance(constructConformanceNode(Conf)); + } +} + void SwiftDeclCollector::printTopLevelNames() { for (auto &Node : RootNode->getChildren()) { llvm::outs() << Node->getKind() << ": " << Node->getName() << '\n'; @@ -1574,7 +1636,7 @@ void SDKNodeDeclType::jsonize(json::Output &out) { output(out, KeyKind::KK_superclassUsr, SuperclassUsr); output(out, KeyKind::KK_enumRawTypeName, EnumRawTypeName); out.mapOptional(getKeyContent(Ctx, KeyKind::KK_superclassNames).data(), SuperclassNames); - out.mapOptional(getKeyContent(Ctx, KeyKind::KK_conformingProtocols).data(), ConformingProtocols); + out.mapOptional(getKeyContent(Ctx, KeyKind::KK_conformances).data(), Conformances); } void SDKNodeType::jsonize(json::Output &out) { diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.h b/tools/swift-api-digester/ModuleAnalyzerNodes.h index 126fdbde752..ecce390eeec 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.h +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.h @@ -37,6 +37,7 @@ #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/USRGeneration.h" #include "swift/AST/GenericSignature.h" +#include "swift/AST/ProtocolConformance.h" #include "swift/Basic/ColorUtils.h" #include "swift/Basic/JSONSerialization.h" #include "swift/Basic/LLVMInitialize.h" @@ -224,7 +225,6 @@ class SDKNode { typedef std::vector::iterator ChildIt; protected: SDKContext &Ctx; -private: StringRef Name; StringRef PrintedName; unsigned TheKind : 4; @@ -264,7 +264,8 @@ public: StringRef getAnnotateComment(NodeAnnotation Anno) const; bool isAnnotatedAs(NodeAnnotation Anno) const; void addChild(SDKNode *Child); - ArrayRef getChildren() const; + NodeVector& getChildren() { return Children; } + ArrayRef getChildren() const { return Children; } bool hasSameChildren(const SDKNode &Other) const; unsigned getChildIndex(const SDKNode *Child) const; SDKNode* getOnlyChild() const; @@ -440,17 +441,19 @@ public: class SDKNodeDeclType: public SDKNodeDecl { StringRef SuperclassUsr; std::vector SuperclassNames; - std::vector ConformingProtocols; + std::vector Conformances; StringRef EnumRawTypeName; public: SDKNodeDeclType(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); StringRef getSuperClassUsr() const { return SuperclassUsr; } ArrayRef getClassInheritanceChain() const { return SuperclassNames; } + void addConformance(SDKNode *Conf); + ArrayRef getConformances() const { return Conformances; } + NodeVector getConformances() { return Conformances; } StringRef getSuperClassName() const { return SuperclassNames.empty() ? StringRef() : SuperclassNames.front(); }; - ArrayRef getAllProtocols() const { return ConformingProtocols; } #define NOMINAL_TYPE_DECL(ID, PARENT) \ bool is##ID() const { return getDeclKind() == DeclKind::ID; } @@ -473,6 +476,33 @@ public: void diagnose(SDKNode *Right) override; }; +/// Keeps track of a conformance; the children of this node are +/// SDKNodeTypeWitness. The conformance node should have no parent since +/// they are stored as an additional property in SDKNodeDeclType. +/// The SDKNode part of the conformance node is constructed using the protocol +/// in the conformance, thus getName() will give us the name of the protocol. +class SDKNodeConformance: public SDKNode { + SDKNodeDeclType *TypeDecl; + friend class SDKNodeDeclType; +public: + SDKNodeConformance(SDKNodeInitInfo Info); + ArrayRef getTypeWitnesses() const { return Children; } + SDKNodeDeclType *getNominalTypeDecl() const { return TypeDecl; } + static bool classof(const SDKNode *N); +}; + +/// Keep track of a type witness of an associated type requirement. These nodes +/// only appear as children of SDKNodeConformance. +/// The SDKNode part of this node is constructed using the associated type decl; +/// thus getName() will give us the name of the associated type. The only child +/// of this node is a type node witnessing the associated type requirement. +class SDKNodeTypeWitness: public SDKNode { +public: + SDKNodeTypeWitness(SDKNodeInitInfo Info); + SDKNodeType *getUnderlyingType() const; + static bool classof(const SDKNode *N); +}; + class SDKNodeDeclOperator : public SDKNodeDecl { public: SDKNodeDeclOperator(SDKNodeInitInfo Info); @@ -617,7 +647,11 @@ public: void printTopLevelNames(); + void addConformancesToTypeDecl(SDKNodeDeclType *Root, NominalTypeDecl* NTD); void addMembersToRoot(SDKNode *Root, IterableDeclContext *Context); + + SDKNode *constructTypeWitnessNode(AssociatedTypeDecl *Assoc, Type Ty); + SDKNode *constructConformanceNode(ProtocolConformance *Conform); SDKNode *constructSubscriptDeclNode(SubscriptDecl *SD); SDKNode *constructAssociatedTypeNode(AssociatedTypeDecl *ATD); SDKNode *constructTypeAliasNode(TypeAliasDecl *TAD); @@ -655,8 +689,8 @@ int deserializeSDKDump(StringRef dumpPath, StringRef OutputPath, int findDeclUsr(StringRef dumpPath, CheckerOptions Opts); -void stringSetDifference(ArrayRef Left, ArrayRef Right, - std::vector &LeftMinusRight, std::vector &RightMinusLeft); +void nodeSetDifference(ArrayRef Left, ArrayRef Right, + NodeVector &LeftMinusRight, NodeVector &RightMinusLeft); } // end of abi namespace } // end of ide namespace diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index d3f2cfb94f3..48d9601a336 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -511,15 +511,20 @@ class SameNameNodeMatcher : public NodeMatcher { PrintedNameAndUSR, }; + static bool isUSRSame(SDKNode *L, SDKNode *R) { + auto *LD = dyn_cast(L); + auto *RD = dyn_cast(R); + if (!LD || !RD) + return false; + return LD->getUsr() == RD->getUsr(); + } + // Given two SDK nodes, figure out the reason for why they have the same name. Optional getNameMatchKind(SDKNode *L, SDKNode *R) { if (L->getKind() != R->getKind()) return None; - auto *LD = L->getAs(); - auto *RD = R->getAs(); - assert(LD && RD); - auto NameEqual = LD->getPrintedName() == RD->getPrintedName(); - auto UsrEqual = LD->getUsr() == RD->getUsr(); + auto NameEqual = L->getPrintedName() == R->getPrintedName(); + auto UsrEqual = isUSRSame(L, R); if (NameEqual && UsrEqual) return NameMatchKind::PrintedNameAndUSR; else if (NameEqual) @@ -679,23 +684,7 @@ void swift::ide::api::SDKNodeDeclType::diagnose(SDKNode *Right) { assert(getDeclKind() == R->getDeclKind()); auto DKind = getDeclKind(); - std::vector LeftMinusRight; - std::vector RightMinusLeft; - swift::ide::api::stringSetDifference(getAllProtocols(), R->getAllProtocols(), - LeftMinusRight, RightMinusLeft); - bool isProtocol = getDeclKind() == DeclKind::Protocol; - std::for_each(LeftMinusRight.begin(), LeftMinusRight.end(), [&](StringRef Name) { - Diags.diagnose(SourceLoc(), diag::conformance_removed, getScreenInfo(), Name, - isProtocol); - }); switch (DKind) { - case DeclKind::Protocol: { - std::for_each(RightMinusLeft.begin(), RightMinusLeft.end(), [&](StringRef Name) { - Diags.diagnose(SourceLoc(), diag::conformance_added, getScreenInfo(), - Name); - }); - break; - } case DeclKind::Class: { auto LSuperClass = getSuperClassName(); auto RSuperClass = R->getSuperClassName(); @@ -911,23 +900,18 @@ namespace { // This is first pass on two given SDKNode trees. This pass removes the common part // of two versions of SDK, leaving only the changed part. class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { - static void removeCommonChildren(NodePtr Left, NodePtr Right) { - llvm::SmallPtrSet LeftToRemove; - llvm::SmallPtrSet RightToRemove; - for (auto LC : Left->getChildren()) { - for (auto RC : Right->getChildren()) { - if (*LC == *RC) { - LeftToRemove.insert(LC); - RightToRemove.insert(RC); - break; - } - } - } - for (NodePtr L : LeftToRemove) - Left->removeChild(L); - for (NodePtr R : RightToRemove) - Right->removeChild(R); + + static void removeCommon(NodeVector &Left, NodeVector &Right) { + NodeVector LeftMinusRight, RightMinusLeft; + nodeSetDifference(Left, Right, LeftMinusRight, RightMinusLeft); + Left = LeftMinusRight; + Right = RightMinusLeft; } + + static void removeCommonChildren(NodePtr Left, NodePtr Right) { + removeCommon(Left->getChildren(), Right->getChildren()); + } + SDKContext &Ctx; UpdatedNodesMap &UpdateMap; @@ -993,6 +977,16 @@ public: D->getScreenInfo()); } } + // Diagnose an inherited protocol has been added. + if (auto *Conf = dyn_cast(Right)) { + auto *TD = Conf->getNominalTypeDecl(); + if (TD->isProtocol()) { + Ctx.getDiags().diagnose(SourceLoc(), diag::conformance_added, + TD->getScreenInfo(), + Conf->getName()); + } + } + return; case NodeMatchReason::Removed: assert(!Right); @@ -1004,6 +998,13 @@ public: AT->getScreenInfo(), LT->getPrintedName()); } } + // Diagnose a protocol conformance has been removed. + if (auto *Conf = dyn_cast(Left)) { + auto *TD = Conf->getNominalTypeDecl(); + Ctx.getDiags().diagnose(SourceLoc(), diag::conformance_removed, + TD->getScreenInfo(), Conf->getName(), + TD->isProtocol()); + } return; case NodeMatchReason::FuncToProperty: case NodeMatchReason::ModernizeEnum: @@ -1032,8 +1033,16 @@ public: SDKNodeKind Kind = Left->getKind(); assert(Kind == SDKNodeKind::Root || *Left != *Right); switch(Kind) { - case SDKNodeKind::Root: case SDKNodeKind::DeclType: { + // Remove common conformances and diagnose conformance changes. + auto LConf = cast(Left)->getConformances(); + auto RConf = cast(Right)->getConformances(); + removeCommon(LConf, RConf); + SameNameNodeMatcher(LConf, RConf, *this).match(); + LLVM_FALLTHROUGH; + } + case SDKNodeKind::Conformance: + case SDKNodeKind::Root: { // If the matched nodes are both modules, remove the contained // type decls that are identical. If the matched nodes are both type decls, // remove the contained function decls that are identical. @@ -1042,7 +1051,7 @@ public: SNMatcher.match(); break; } - + case SDKNodeKind::TypeWitness: case SDKNodeKind::DeclOperator: case SDKNodeKind::DeclSubscript: case SDKNodeKind::DeclAssociatedType: