| #include <ModuleAnalyzerNodes.h> |
| #include <algorithm> |
| |
| using namespace swift; |
| using namespace ide; |
| using namespace api; |
| |
| namespace fs = llvm::sys::fs; |
| namespace path = llvm::sys::path; |
| |
| namespace { |
| |
| enum class KeyKind { |
| #define KEY(NAME) KK_##NAME, |
| #include "swift/IDE/DigesterEnums.def" |
| }; |
| |
| /// The additional information we need to create a type node. |
| struct TypeInitInfo { |
| bool IsImplicitlyUnwrappedOptional = false; |
| /// When this type node represents a function parameter, this boolean value |
| /// indicates whether the parameter has default argument. |
| bool hasDefaultArgument = false; |
| }; |
| |
| static StringRef getAttrName(DeclAttrKind Kind) { |
| switch (Kind) { |
| #define DECL_ATTR(NAME, CLASS, ...) \ |
| case DAK_##CLASS: \ |
| return DeclAttribute::isDeclModifier(DAK_##CLASS) ? #NAME : "@"#NAME; |
| #include "swift/AST/Attr.def" |
| case DAK_Count: |
| llvm_unreachable("unrecognized attribute kind."); |
| } |
| } |
| } // End of anonymous namespace. |
| |
| struct swift::ide::api::SDKNodeInitInfo { |
| SDKContext &Ctx; |
| StringRef Name; |
| StringRef PrintedName; |
| DeclKind DKind; |
| StringRef USR; |
| StringRef Location; |
| StringRef ModuleName; |
| bool IsImplicit = false; |
| bool IsThrowing = false; |
| bool IsMutating = false; |
| bool IsStatic = false; |
| bool IsDeprecated = false; |
| Optional<uint8_t> SelfIndex; |
| Optional<unsigned> FixedBinaryOrder; |
| ReferenceOwnership ReferenceOwnership = ReferenceOwnership::Strong; |
| std::vector<DeclAttrKind> DeclAttrs; |
| std::vector<TypeAttrKind> TypeAttrs; |
| std::vector<StringRef> ConformingProtocols; |
| StringRef SuperclassUsr; |
| StringRef EnumRawTypeName; |
| TypeInitInfo TypeInfo; |
| StringRef GenericSig; |
| bool HasSetter = false; |
| |
| SDKNodeInitInfo(SDKContext &Ctx) : Ctx(Ctx) {} |
| SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD); |
| SDKNodeInitInfo(SDKContext &Ctx, Type Ty, TypeInitInfo Info = TypeInitInfo()); |
| SDKNode* createSDKNode(SDKNodeKind Kind); |
| }; |
| |
| SDKContext::SDKContext(CheckerOptions Opts): Diags(SourceMgr), Opts(Opts) { |
| #define ADD(NAME) ABIAttrs.push_back({DeclAttrKind::DAK_##NAME, \ |
| getAttrName(DeclAttrKind::DAK_##NAME)}); |
| ADD(ObjC) |
| ADD(FixedLayout) |
| ADD(Frozen) |
| ADD(Dynamic) |
| #undef ADD |
| } |
| |
| |
| SDKNode::SDKNode(SDKNodeInitInfo Info, SDKNodeKind Kind): Ctx(Info.Ctx), |
| Name(Info.Name), PrintedName(Info.PrintedName), TheKind(unsigned(Kind)) {} |
| |
| SDKNodeRoot::SDKNodeRoot(SDKNodeInitInfo Info): SDKNode(Info, SDKNodeKind::Root) {} |
| |
| SDKNodeDecl::SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind) |
| : SDKNode(Info, Kind), DKind(Info.DKind), Usr(Info.USR), |
| Location(Info.Location), ModuleName(Info.ModuleName), |
| DeclAttributes(Info.DeclAttrs), IsImplicit(Info.IsImplicit), |
| IsStatic(Info.IsStatic), IsDeprecated(Info.IsDeprecated), |
| ReferenceOwnership(uint8_t(Info.ReferenceOwnership)), |
| GenericSig(Info.GenericSig) {} |
| |
| SDKNodeType::SDKNodeType(SDKNodeInitInfo Info, SDKNodeKind Kind): |
| SDKNode(Info, Kind), TypeAttributes(Info.TypeAttrs), |
| HasDefaultArg(Info.TypeInfo.hasDefaultArgument) {} |
| |
| SDKNodeTypeNominal::SDKNodeTypeNominal(SDKNodeInitInfo Info): |
| SDKNodeType(Info, SDKNodeKind::TypeNominal), USR(Info.USR) {} |
| |
| SDKNodeTypeFunc::SDKNodeTypeFunc(SDKNodeInitInfo Info): |
| SDKNodeType(Info, SDKNodeKind::TypeFunc) {} |
| |
| SDKNodeTypeAlias::SDKNodeTypeAlias(SDKNodeInitInfo Info): |
| SDKNodeType(Info, SDKNodeKind::TypeAlias) {} |
| |
| SDKNodeDeclType::SDKNodeDeclType(SDKNodeInitInfo Info): |
| SDKNodeDecl(Info, SDKNodeKind::DeclType), SuperclassUsr(Info.SuperclassUsr), |
| ConformingProtocols(Info.ConformingProtocols), |
| EnumRawTypeName(Info.EnumRawTypeName) {} |
| |
| SDKNodeDeclTypeAlias::SDKNodeDeclTypeAlias(SDKNodeInitInfo Info): |
| SDKNodeDecl(Info, SDKNodeKind::DeclTypeAlias) {} |
| |
| SDKNodeDeclVar::SDKNodeDeclVar(SDKNodeInitInfo Info): |
| SDKNodeDecl(Info, SDKNodeKind::DeclVar), |
| FixedBinaryOrder(Info.FixedBinaryOrder) {} |
| |
| SDKNodeDeclAbstractFunc::SDKNodeDeclAbstractFunc(SDKNodeInitInfo Info, |
| SDKNodeKind Kind): SDKNodeDecl(Info, Kind), IsThrowing(Info.IsThrowing), |
| IsMutating(Info.IsMutating), SelfIndex(Info.SelfIndex) {} |
| |
| SDKNodeDeclFunction::SDKNodeDeclFunction(SDKNodeInitInfo Info): |
| SDKNodeDeclAbstractFunc(Info, SDKNodeKind::DeclFunction) {} |
| |
| SDKNodeDeclConstructor::SDKNodeDeclConstructor(SDKNodeInitInfo Info): |
| SDKNodeDeclAbstractFunc(Info, SDKNodeKind::DeclConstructor) {} |
| |
| SDKNodeDeclGetter::SDKNodeDeclGetter(SDKNodeInitInfo Info): |
| SDKNodeDeclAbstractFunc(Info, SDKNodeKind::DeclGetter) {} |
| |
| SDKNodeDeclSetter::SDKNodeDeclSetter(SDKNodeInitInfo Info): |
| SDKNodeDeclAbstractFunc(Info, SDKNodeKind::DeclSetter) {} |
| |
| SDKNodeDeclAssociatedType::SDKNodeDeclAssociatedType(SDKNodeInitInfo Info): |
| SDKNodeDecl(Info, SDKNodeKind::DeclAssociatedType) {}; |
| |
| SDKNodeDeclSubscript::SDKNodeDeclSubscript(SDKNodeInitInfo Info): |
| SDKNodeDeclAbstractFunc(Info, SDKNodeKind::DeclSubscript), |
| HasSetter(Info.HasSetter) {} |
| |
| StringRef SDKNodeDecl::getHeaderName() const { |
| if (Location.empty()) |
| return StringRef(); |
| return llvm::sys::path::filename(Location.split(":").first); |
| } |
| |
| SDKNodeDeclGetter *SDKNodeDeclVar::getGetter() const { |
| if (getChildrenCount() > 1) |
| return cast<SDKNodeDeclGetter>(childAt(1)); |
| return nullptr; |
| } |
| |
| SDKNodeDeclSetter *SDKNodeDeclVar::getSetter() const { |
| if (getChildrenCount() > 2) |
| return cast<SDKNodeDeclSetter>(childAt(2)); |
| return nullptr; |
| } |
| |
| SDKNodeType *SDKNodeDeclVar::getType() const { |
| return cast<SDKNodeType>(childAt(0)); |
| } |
| |
| NodePtr UpdatedNodesMap::findUpdateCounterpart(const SDKNode *Node) const { |
| assert(Node->isAnnotatedAs(NodeAnnotation::Updated) && "Not update operation."); |
| auto FoundPair = std::find_if(MapImpl.begin(), MapImpl.end(), |
| [&](std::pair<NodePtr, NodePtr> Pair) { |
| return Pair.second == Node || Pair.first == Node; |
| }); |
| assert(FoundPair != MapImpl.end() && "Cannot find update counterpart."); |
| return Node == FoundPair->first ? FoundPair->second : FoundPair->first; |
| } |
| |
| bool SDKNodeType::classof(const SDKNode *N) { |
| switch (N->getKind()) { |
| case SDKNodeKind::TypeNominal: |
| case SDKNodeKind::TypeFunc: |
| case SDKNodeKind::TypeAlias: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| unsigned SDKNode::getChildIndex(const SDKNode* Child) const { |
| auto It = std::find(Children.begin(), Children.end(), Child); |
| assert(It != Children.end() && "cannot find the child"); |
| return It - Children.begin(); |
| } |
| |
| SDKNode* SDKNode::getOnlyChild() const { |
| assert(Children.size() == 1 && "more that one child."); |
| return *Children.begin(); |
| } |
| |
| SDKNodeRoot *SDKNode::getRootNode() const { |
| for (auto *Root = const_cast<SDKNode*>(this); ; Root = Root->getParent()) { |
| if (auto Result = dyn_cast<SDKNodeRoot>(Root)) |
| return Result; |
| } |
| llvm_unreachable("Unhandled SDKNodeKind in switch."); |
| } |
| |
| void SDKNode::addChild(SDKNode *Child) { |
| Child->Parent = this; |
| Children.push_back(Child); |
| if (auto *Root = dyn_cast<SDKNodeRoot>(this)) { |
| struct DeclCollector: public SDKNodeVisitor { |
| SDKNodeRoot &Root; |
| DeclCollector(SDKNodeRoot &Root): Root(Root) {} |
| void visit(NodePtr Node) override { |
| Root.registerDescendant(Node); |
| } |
| } Collector(*Root); |
| SDKNode::preorderVisit(Child, Collector); |
| } |
| } |
| |
| ArrayRef<SDKNode*> SDKNode::getChildren() const { |
| return llvm::makeArrayRef(Children); |
| } |
| |
| NodePtr SDKNode::childAt(unsigned I) const { |
| assert(I < getChildrenCount()); |
| return getChildren()[I]; |
| } |
| |
| void SDKNode::removeChild(NodePtr C) { |
| Children.erase(std::find(Children.begin(), Children.end(), C)); |
| } |
| |
| void SDKNode::annotate(NodeAnnotation Anno, StringRef Comment) { |
| assert(!Comment.empty()); |
| if(isAnnotatedAs(Anno)) |
| return; |
| annotate(Anno); |
| AnnotateComments[Anno] = Comment; |
| } |
| |
| void SDKNode::removeAnnotate(NodeAnnotation Anno) { |
| assert(isAnnotatedAs(Anno)); |
| Annotations.erase(Anno); |
| AnnotateComments.erase(Anno); |
| assert(!isAnnotatedAs(Anno)); |
| assert(AnnotateComments.count(Anno) == 0); |
| } |
| |
| StringRef SDKNode::getAnnotateComment(NodeAnnotation Anno) const { |
| return AnnotateComments.find(Anno)->second; |
| } |
| |
| ArrayRef<NodeAnnotation> SDKNode:: |
| getAnnotations(std::vector<NodeAnnotation> &Scratch) const { |
| for (auto Ann : Annotations) |
| Scratch.push_back(Ann); |
| return llvm::makeArrayRef(Scratch); |
| } |
| |
| bool SDKNode::isAnnotatedAs(NodeAnnotation Anno) const { |
| return Annotations.find(Anno) != Annotations.end();; |
| } |
| |
| void SDKNode::preorderVisit(NodePtr Root, SDKNodeVisitor &Visitor) { |
| Visitor.visit(Root); |
| Visitor.Ancestors.push_back(Root); |
| for (auto Child : Root->Children) |
| preorderVisit(Child, Visitor); |
| Visitor.Ancestors.pop_back(); |
| } |
| |
| void SDKNode::postorderVisit(NodePtr Root, SDKNodeVisitor &Visitor) { |
| Visitor.Ancestors.push_back(Root); |
| for (auto Child : Root->Children) |
| postorderVisit(Child, Visitor); |
| Visitor.Ancestors.pop_back(); |
| Visitor.visit(Root); |
| } |
| |
| SDKNodeVectorViewer::VectorIt |
| SDKNodeVectorViewer::getNext(VectorIt Start) { |
| for (auto It = Start; It != Collection.end(); ++ It) |
| if (Selector(*It)) |
| return It; |
| return Collection.end(); |
| } |
| |
| SDKNodeVectorViewer::ViewerIterator& |
| SDKNodeVectorViewer::ViewerIterator::operator++() { |
| P = Viewer.getNext(P + 1); |
| return *this; |
| } |
| |
| SDKNodeVectorViewer::ViewerIterator SDKNodeVectorViewer::begin() { |
| return ViewerIterator(*this, getNext(Collection.begin())); |
| } |
| |
| SDKNodeVectorViewer::ViewerIterator SDKNodeVectorViewer::end() { |
| return ViewerIterator(*this, Collection.end()); |
| } |
| |
| KnownTypeKind SDKNodeType::getTypeKind() const { |
| #define KNOWN_TYPE(NAME) if (getName() == #NAME) return KnownTypeKind::NAME; |
| #include "swift/IDE/DigesterEnums.def" |
| return KnownTypeKind::Unknown; |
| } |
| |
| ArrayRef<TypeAttrKind> SDKNodeType::getTypeAttributes() const { |
| return llvm::makeArrayRef(TypeAttributes.data(), TypeAttributes.size()); |
| } |
| |
| void SDKNodeType::addTypeAttribute(TypeAttrKind AttrKind) { |
| TypeAttributes.push_back(AttrKind); |
| } |
| |
| bool SDKNodeType::hasTypeAttribute(TypeAttrKind DAKind) const { |
| return std::find(TypeAttributes.begin(), TypeAttributes.end(), DAKind) != |
| TypeAttributes.end(); |
| } |
| |
| SDKNode *SDKNodeRoot::getInstance(SDKContext &Ctx) { |
| SDKNodeInitInfo Info(Ctx); |
| Info.Name = Ctx.buffer("TopLevel"); |
| Info.PrintedName = Ctx.buffer("TopLevel"); |
| return Info.createSDKNode(SDKNodeKind::Root); |
| } |
| |
| StringRef SDKNodeDecl::getScreenInfo() const { |
| auto ModuleName = getModuleName(); |
| auto HeaderName = getHeaderName(); |
| auto &Ctx = getSDKContext(); |
| llvm::SmallString<64> SS; |
| llvm::raw_svector_ostream OS(SS); |
| if (Ctx.getOpts().PrintModule) |
| OS << ModuleName; |
| if (!HeaderName.empty()) |
| OS << "(" << HeaderName << ")"; |
| if (!OS.str().empty()) |
| OS << ": "; |
| OS << getDeclKind() << " " << getFullyQualifiedName(); |
| return Ctx.buffer(OS.str()); |
| } |
| |
| bool SDKNodeDecl::isSDKPrivate() const { |
| if (getName().startswith("__")) |
| return true; |
| if (auto *PD = dyn_cast<SDKNodeDecl>(getParent())) |
| return PD->isSDKPrivate(); |
| return false; |
| } |
| |
| void SDKNodeDecl::printFullyQualifiedName(llvm::raw_ostream &OS) const { |
| std::vector<NodePtr> Parent; |
| for (auto *P = getParent(); isa<SDKNodeDecl>(P); P = P->getParent()) |
| Parent.push_back(P); |
| for (auto It = Parent.rbegin(); It != Parent.rend(); ++ It) |
| OS << (*It)->getPrintedName() << "."; |
| OS << getPrintedName(); |
| } |
| |
| StringRef SDKNodeDecl::getFullyQualifiedName() const { |
| llvm::SmallString<32> Buffer; |
| llvm::raw_svector_ostream OS(Buffer); |
| printFullyQualifiedName(OS); |
| return getSDKContext().buffer(OS.str()); |
| } |
| |
| bool SDKNodeDecl::classof(const SDKNode *N) { |
| switch (N->getKind()) { |
| case SDKNodeKind::DeclConstructor: |
| case SDKNodeKind::DeclFunction: |
| case SDKNodeKind::DeclGetter: |
| case SDKNodeKind::DeclSetter: |
| case SDKNodeKind::DeclTypeAlias: |
| case SDKNodeKind::DeclType: |
| case SDKNodeKind::DeclVar: |
| case SDKNodeKind::DeclAssociatedType: |
| case SDKNodeKind::DeclSubscript: |
| return true; |
| case SDKNodeKind::Root: |
| case SDKNodeKind::TypeNominal: |
| case SDKNodeKind::TypeFunc: |
| case SDKNodeKind::TypeAlias: |
| return false; |
| } |
| |
| llvm_unreachable("Unhandled SDKNodeKind in switch."); |
| } |
| |
| bool SDKNodeDecl::hasDeclAttribute(DeclAttrKind DAKind) const { |
| return std::find(DeclAttributes.begin(), DeclAttributes.end(), DAKind) != |
| DeclAttributes.end(); |
| } |
| |
| ArrayRef<DeclAttrKind> SDKNodeDecl::getDeclAttributes() const { |
| return llvm::makeArrayRef(DeclAttributes.data(), DeclAttributes.size()); |
| } |
| |
| bool SDKNodeDecl::hasAttributeChange(const SDKNodeDecl &Another) const { |
| if (getDeclAttributes().size() != Another.getDeclAttributes().size()) |
| return true; |
| for (auto K: getDeclAttributes()) { |
| if (!Another.hasDeclAttribute(K)) |
| return true; |
| } |
| return false; |
| } |
| |
| SDKNodeDecl *SDKNodeType::getClosestParentDecl() const { |
| auto *Result = getParent(); |
| for (; !isa<SDKNodeDecl>(Result); Result = Result->getParent()); |
| return Result->getAs<SDKNodeDecl>(); |
| } |
| |
| Optional<SDKNodeDeclType*> SDKNodeDeclType::getSuperclass() const { |
| if (SuperclassUsr.empty()) |
| return None; |
| auto Descendants = getRootNode()->getDescendantsByUsr(SuperclassUsr); |
| if (!Descendants.empty()) { |
| return Descendants.front()->getAs<SDKNodeDeclType>(); |
| } |
| return None; |
| } |
| |
| /// Finding the node through all children, including the inheritted ones, |
| /// whose printed name matches with the given name. |
| Optional<SDKNodeDecl*> |
| SDKNodeDeclType::lookupChildByPrintedName(StringRef Name) const { |
| for (auto C : getChildren()) { |
| if (C->getPrintedName() == Name) |
| return C->getAs<SDKNodeDecl>(); |
| } |
| // Finding from the inheritance chain. |
| if (auto Super = getSuperclass()) { |
| return (*Super)->lookupChildByPrintedName(Name); |
| } |
| return None; |
| } |
| |
| SDKNodeType *SDKNodeDeclType::getRawValueType() const { |
| if (isConformingTo(KnownProtocolKind::RawRepresentable)) { |
| if (auto RV = lookupChildByPrintedName("rawValue")) { |
| return (*(*RV)->getChildBegin())->getAs<SDKNodeType>(); |
| } |
| } |
| return nullptr; |
| } |
| |
| 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(); |
| #include "swift/IDE/DigesterEnums.def" |
| } |
| } |
| |
| bool SDKNodeDeclAbstractFunc::classof(const SDKNode *N) { |
| switch (N->getKind()) { |
| case SDKNodeKind::DeclFunction: |
| case SDKNodeKind::DeclSetter: |
| case SDKNodeKind::DeclGetter: |
| case SDKNodeKind::DeclConstructor: |
| case SDKNodeKind::DeclSubscript: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| StringRef SDKNodeDeclAbstractFunc::getTypeRoleDescription(SDKContext &Ctx, |
| unsigned Index) { |
| if (Index == 0) { |
| return Ctx.buffer("return"); |
| } else { |
| llvm::SmallString<4> Buffer; |
| Buffer += "parameter "; |
| Buffer += std::to_string(Index - 1); |
| return Ctx.buffer(Buffer.str()); |
| } |
| } |
| |
| #define NODE_KIND(X, NAME) \ |
| bool SDKNode##X::classof(const SDKNode *N) { \ |
| return N->getKind() == SDKNodeKind::X; \ |
| } |
| #include "swift/IDE/DigesterEnums.def" |
| |
| static Optional<KeyKind> parseKeyKind(StringRef Content) { |
| return llvm::StringSwitch<Optional<KeyKind>>(Content) |
| #define KEY(NAME) .Case(#NAME, KeyKind::KK_##NAME) |
| #include "swift/IDE/DigesterEnums.def" |
| .Default(None) |
| ; |
| } |
| |
| static StringRef getKeyContent(SDKContext &Ctx, KeyKind Kind) { |
| switch (Kind) { |
| #define KEY(NAME) case KeyKind::KK_##NAME: return Ctx.buffer(#NAME); |
| #include "swift/IDE/DigesterEnums.def" |
| } |
| llvm_unreachable("Unhandled KeyKind in switch."); |
| } |
| |
| SDKNode* SDKNode::constructSDKNode(SDKContext &Ctx, |
| llvm::yaml::MappingNode *Node) { |
| static auto GetScalarString = [&](llvm::yaml::Node *N) -> StringRef { |
| auto WithQuote = cast<llvm::yaml::ScalarNode>(N)->getRawValue(); |
| return WithQuote.substr(1, WithQuote.size() - 2); |
| }; |
| |
| static auto getAsInt = [&](llvm::yaml::Node *N) -> int { |
| return std::stoi(cast<llvm::yaml::ScalarNode>(N)->getRawValue()); |
| }; |
| |
| SDKNodeKind Kind; |
| SDKNodeInitInfo Info(Ctx); |
| NodeVector Children; |
| |
| for (auto &Pair : *Node) { |
| auto keyString = GetScalarString(Pair.getKey()); |
| if (auto keyKind = parseKeyKind(keyString)) { |
| switch(*keyKind) { |
| case KeyKind::KK_kind: |
| if (auto parsedKind = parseSDKNodeKind(GetScalarString(Pair.getValue()))) { |
| Kind = *parsedKind; |
| } else { |
| Ctx.diagnose(Pair.getValue(), diag::sdk_node_unrecognized_node_kind, |
| GetScalarString(Pair.getValue())); |
| } |
| break; |
| case KeyKind::KK_name: |
| Info.Name = GetScalarString(Pair.getValue()); |
| break; |
| case KeyKind::KK_selfIndex: |
| Info.SelfIndex = getAsInt(Pair.getValue()); |
| break; |
| case KeyKind::KK_fixedbinaryorder: |
| Info.FixedBinaryOrder = getAsInt(Pair.getValue()); |
| break; |
| case KeyKind::KK_usr: |
| Info.USR = GetScalarString(Pair.getValue()); |
| break; |
| |
| case KeyKind::KK_location: |
| Info.Location = GetScalarString(Pair.getValue()); |
| break; |
| case KeyKind::KK_children: |
| for (auto &Mapping : *cast<llvm::yaml::SequenceNode>(Pair.getValue())) { |
| Children.push_back(constructSDKNode(Ctx, |
| cast<llvm::yaml::MappingNode>(&Mapping))); |
| } |
| break; |
| case KeyKind::KK_conformingProtocols: { |
| assert(Info.ConformingProtocols.empty()); |
| for (auto &Name : *cast<llvm::yaml::SequenceNode>(Pair.getValue())) { |
| Info.ConformingProtocols.push_back(GetScalarString(&Name)); |
| } |
| break; |
| } |
| case KeyKind::KK_enumRawTypeName: { |
| assert(Info.DKind == DeclKind::Enum); |
| Info.EnumRawTypeName = GetScalarString(Pair.getValue()); |
| break; |
| } |
| case KeyKind::KK_printedName: |
| Info.PrintedName = GetScalarString(Pair.getValue()); |
| break; |
| case KeyKind::KK_moduleName: |
| Info.ModuleName = GetScalarString(Pair.getValue()); |
| break; |
| case KeyKind::KK_superclassUsr: |
| Info.SuperclassUsr = GetScalarString(Pair.getValue()); |
| break; |
| case KeyKind::KK_genericSig: |
| Info.GenericSig = GetScalarString(Pair.getValue()); |
| break; |
| case KeyKind::KK_throwing: |
| Info.IsThrowing = true; |
| break; |
| case KeyKind::KK_mutating: |
| Info.IsMutating = true; |
| break; |
| case KeyKind::KK_hasDefaultArg: |
| Info.TypeInfo.hasDefaultArgument = true; |
| break; |
| case KeyKind::KK_static: |
| Info.IsStatic = true; |
| break; |
| case KeyKind::KK_deprecated: |
| Info.IsDeprecated = true; |
| break; |
| case KeyKind::KK_implicit: |
| Info.IsImplicit = true; |
| break; |
| case KeyKind::KK_hasSetter: |
| Info.HasSetter = true; |
| break; |
| case KeyKind::KK_ownership: |
| Info.ReferenceOwnership = |
| swift::ReferenceOwnership(getAsInt(Pair.getValue())); |
| assert(Info.ReferenceOwnership != swift::ReferenceOwnership::Strong && |
| "Strong is implied."); |
| break; |
| |
| case KeyKind::KK_typeAttributes: { |
| auto *Seq = cast<llvm::yaml::SequenceNode>(Pair.getValue()); |
| std::transform(Seq->begin(), Seq->end(), |
| std::back_inserter(Info.TypeAttrs), |
| [&](llvm::yaml::Node &N) { |
| auto Result = llvm::StringSwitch<TypeAttrKind>(GetScalarString(&N)) |
| #define TYPE_ATTR(X) .Case(#X, TypeAttrKind::TAK_##X) |
| #include "swift/AST/Attr.def" |
| .Default(TypeAttrKind::TAK_Count); |
| if (Result == TAK_Count) |
| Ctx.diagnose(&N, diag::sdk_node_unrecognized_type_attr_kind, |
| GetScalarString(&N)); |
| return Result; |
| }); |
| break; |
| } |
| case KeyKind::KK_declAttributes: { |
| auto *Seq = cast<llvm::yaml::SequenceNode>(Pair.getValue()); |
| std::transform(Seq->begin(), Seq->end(), std::back_inserter(Info.DeclAttrs), |
| [&](llvm::yaml::Node &N) { |
| auto Result = llvm::StringSwitch<DeclAttrKind>(GetScalarString(&N)) |
| #define DECL_ATTR(_, NAME, ...) .Case(#NAME, DeclAttrKind::DAK_##NAME) |
| #include "swift/AST/Attr.def" |
| .Default(DeclAttrKind::DAK_Count); |
| if (Result == DAK_Count) |
| Ctx.diagnose(&N, diag::sdk_node_unrecognized_decl_attr_kind, |
| GetScalarString(&N)); |
| return Result; |
| }); |
| break; |
| } |
| case KeyKind::KK_declKind: { |
| auto dKind = llvm::StringSwitch<Optional<DeclKind>>( |
| GetScalarString(Pair.getValue())) |
| #define DECL(X, PARENT) .Case(#X, DeclKind::X) |
| #include "swift/AST/DeclNodes.def" |
| .Default(None); |
| if (dKind) |
| Info.DKind = *dKind; |
| else |
| Ctx.diagnose(Pair.getValue(), diag::sdk_node_unrecognized_decl_kind, |
| GetScalarString(Pair.getValue())); |
| break; |
| } |
| } |
| } |
| else { |
| Ctx.diagnose(Pair.getKey(), diag::sdk_node_unrecognized_key, |
| keyString); |
| Pair.skip(); |
| } |
| }; |
| SDKNode *Result = Info.createSDKNode(Kind); |
| for (auto C : Children) { |
| Result->addChild(C); |
| } |
| return Result; |
| } |
| |
| bool SDKNode::hasSameChildren(const SDKNode &Other) const { |
| if (Children.size() != Other.Children.size()) |
| return false; |
| for (unsigned I = 0; I < Children.size(); ++ I) { |
| if (*Children[I] != *Other.Children[I]) |
| return false; |
| } |
| return true; |
| } |
| |
| void swift::ide::api::stringSetDifference(ArrayRef<StringRef> Left, |
| ArrayRef<StringRef> Right, |
| std::vector<StringRef> &LeftMinusRight, |
| std::vector<StringRef> &RightMinusLeft) { |
| std::set<StringRef> LS(Left.begin(), Left.end()); |
| std::set<StringRef> 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)); |
| } |
| |
| static bool hasSameContents(ArrayRef<StringRef> Left, |
| ArrayRef<StringRef> Right) { |
| std::vector<StringRef> LeftMinusRight, RightMinusLeft; |
| stringSetDifference(Left, Right, LeftMinusRight, RightMinusLeft); |
| return LeftMinusRight.empty() && RightMinusLeft.empty(); |
| } |
| |
| bool SDKNode::operator==(const SDKNode &Other) const { |
| auto *LeftAlias = dyn_cast<SDKNodeTypeAlias>(this); |
| auto *RightAlias = dyn_cast<SDKNodeTypeAlias>(&Other); |
| if (LeftAlias || RightAlias) { |
| // Comparing the underlying types if any of the inputs are alias. |
| const SDKNode *Left = LeftAlias ? LeftAlias->getUnderlyingType() : this; |
| const SDKNode *Right = RightAlias ? RightAlias->getUnderlyingType() : &Other; |
| return *Left == *Right; |
| } |
| |
| if (getKind() != Other.getKind()) |
| return false; |
| |
| switch(getKind()) { |
| case SDKNodeKind::TypeAlias: |
| llvm_unreachable("Should be handled above."); |
| case SDKNodeKind::TypeNominal: |
| case SDKNodeKind::TypeFunc: { |
| auto Left = this->getAs<SDKNodeType>(); |
| auto Right = (&Other)->getAs<SDKNodeType>(); |
| if (!Left->getTypeAttributes().equals(Right->getTypeAttributes())) |
| return false; |
| if (Left->hasDefaultArgument() != Right->hasDefaultArgument()) |
| return false; |
| if (Left->getPrintedName() == Right->getPrintedName()) |
| return true; |
| return Left->getName() == Right->getName() && |
| Left->hasSameChildren(*Right); |
| } |
| |
| case SDKNodeKind::DeclFunction: |
| case SDKNodeKind::DeclConstructor: |
| case SDKNodeKind::DeclGetter: |
| case SDKNodeKind::DeclSetter: { |
| auto Left = this->getAs<SDKNodeDeclAbstractFunc>(); |
| auto Right = (&Other)->getAs<SDKNodeDeclAbstractFunc>(); |
| if (Left->isMutating() ^ Right->isMutating()) |
| return false; |
| if (Left->isThrowing() ^ Right->isThrowing()) |
| return false; |
| LLVM_FALLTHROUGH; |
| } |
| |
| case SDKNodeKind::DeclVar: { |
| if (getSDKContext().checkingABI()) { |
| // If we're checking ABI, the definition order matters. |
| // If they're both members for fixed layout types, we never consider |
| // them equal because we need to check definition orders. |
| if (auto *LV = dyn_cast<SDKNodeDeclVar>(this)) { |
| if (auto *RV = dyn_cast<SDKNodeDeclVar>(&Other)) { |
| if (LV->hasFixedBinaryOrder() && RV->hasFixedBinaryOrder()) { |
| if (LV->getFixedBinaryOrder() != RV->getFixedBinaryOrder()) |
| return false; |
| } |
| } |
| } |
| } |
| LLVM_FALLTHROUGH; |
| } |
| case SDKNodeKind::DeclType: { |
| auto *Left = dyn_cast<SDKNodeDeclType>(this); |
| auto *Right = dyn_cast<SDKNodeDeclType>(&Other); |
| if (Left && Right) { |
| if (!hasSameContents(Left->getAllProtocols(), Right->getAllProtocols())) { |
| return false; |
| } |
| } |
| LLVM_FALLTHROUGH; |
| } |
| case SDKNodeKind::DeclAssociatedType: |
| case SDKNodeKind::DeclSubscript: { |
| auto *Left = dyn_cast<SDKNodeDeclSubscript>(this); |
| auto *Right = dyn_cast<SDKNodeDeclSubscript>(&Other); |
| if (Left && Right && Left->hasSetter() != Right->hasSetter()) |
| return false; |
| LLVM_FALLTHROUGH; |
| } |
| case SDKNodeKind::DeclTypeAlias: { |
| auto Left = this->getAs<SDKNodeDecl>(); |
| auto Right = (&Other)->getAs<SDKNodeDecl>(); |
| if (Left->isStatic() ^ Right->isStatic()) |
| return false; |
| if (Left->getReferenceOwnership() != Right->getReferenceOwnership()) |
| return false; |
| if (Left->hasAttributeChange(*Right)) |
| return false; |
| if (Left->getGenericSignature() != Right->getGenericSignature()) |
| return false; |
| |
| LLVM_FALLTHROUGH; |
| } |
| case SDKNodeKind::Root: { |
| return getPrintedName() == Other.getPrintedName() && |
| hasSameChildren(Other); |
| } |
| } |
| |
| llvm_unreachable("Unhanlded SDKNodeKind in switch."); |
| } |
| |
| // The pretty printer of a tree of SDKNode |
| class SDKNodeDumpVisitor : public SDKNodeVisitor { |
| void dumpSpace(int Num) { |
| while (Num != 0) { |
| llvm::outs() << "\t"; |
| Num --; |
| } |
| } |
| void visit(NodePtr Node) override { |
| dumpSpace(depth()); |
| llvm::outs() << "[" << Node->getKind() << "]" << Node->getName() << "\n"; |
| } |
| public: |
| SDKNodeDumpVisitor() {}; |
| }; |
| |
| static StringRef getPrintedName(SDKContext &Ctx, Type Ty, |
| bool IsImplicitlyUnwrappedOptional) { |
| std::string S; |
| llvm::raw_string_ostream OS(S); |
| PrintOptions PO; |
| PO.SkipAttributes = true; |
| if (IsImplicitlyUnwrappedOptional) |
| PO.PrintOptionalAsImplicitlyUnwrapped = true; |
| |
| Ty.print(OS, PO); |
| return Ctx.buffer(OS.str()); |
| } |
| |
| static StringRef getTypeName(SDKContext &Ctx, Type Ty, |
| bool IsImplicitlyUnwrappedOptional) { |
| if (Ty->getKind() == TypeKind::Paren) { |
| return Ctx.buffer("Paren"); |
| } |
| if (Ty->isVoid()) { |
| return Ctx.buffer("Void"); |
| } |
| if (auto *NAT = dyn_cast<NameAliasType>(Ty.getPointer())) { |
| return NAT->getDecl()->getNameStr(); |
| } |
| if (Ty->getAnyNominal()) { |
| if (IsImplicitlyUnwrappedOptional) { |
| assert(Ty->getOptionalObjectType()); |
| return StringRef("ImplicitlyUnwrappedOptional"); |
| } |
| return Ty->getAnyNominal()->getNameStr(); |
| } |
| #define TYPE(id, parent) \ |
| if (Ty->getKind() == TypeKind::id) { \ |
| return Ctx.buffer(#id); \ |
| } |
| #include "swift/AST/TypeNodes.def" |
| llvm_unreachable("Unhandled type name."); |
| } |
| |
| static StringRef calculateUsr(SDKContext &Ctx, ValueDecl *VD) { |
| llvm::SmallString<64> SS; |
| llvm::raw_svector_ostream OS(SS); |
| if (!ide::printDeclUSR(VD, OS)) { |
| return Ctx.buffer(SS.str()); |
| } |
| return StringRef(); |
| } |
| |
| static StringRef calculateLocation(SDKContext &SDKCtx, ValueDecl *VD) { |
| if (SDKCtx.getOpts().AvoidLocation) |
| return StringRef(); |
| auto &Ctx = VD->getASTContext(); |
| auto &Importer = static_cast<ClangImporter &>(*Ctx.getClangModuleLoader()); |
| |
| clang::SourceManager &SM = Importer.getClangPreprocessor().getSourceManager(); |
| if (ClangNode CN = VD->getClangNode()) { |
| clang::SourceLocation Loc = CN.getLocation(); |
| Loc = SM.getFileLoc(Loc); |
| if (Loc.isValid()) |
| return SDKCtx.buffer(Loc.printToString(SM)); |
| } |
| |
| return StringRef(); |
| } |
| |
| static bool isFunctionTypeNoEscape(Type Ty) { |
| if (auto *AFT = Ty->getAs<AnyFunctionType>()) { |
| return AFT->getExtInfo().isNoEscape(); |
| } |
| return false; |
| } |
| |
| /// Converts a DeclBaseName to a string by assigning special names strings and |
| /// escaping identifiers that would clash with these strings using '`' |
| static StringRef getEscapedName(DeclBaseName name) { |
| switch (name.getKind()) { |
| case DeclBaseName::Kind::Subscript: |
| return "subscript"; |
| case DeclBaseName::Kind::Constructor: |
| return "init"; |
| case DeclBaseName::Kind::Destructor: |
| return "deinit"; |
| case DeclBaseName::Kind::Normal: |
| return llvm::StringSwitch<StringRef>(name.getIdentifier().str()) |
| .Case("subscript", "`subscript`") |
| .Case("init", "`init`") |
| .Case("deinit", "`deinit`") |
| .Default(name.getIdentifier().str()); |
| } |
| } |
| |
| static StringRef getPrintedName(SDKContext &Ctx, ValueDecl *VD) { |
| llvm::SmallString<32> Result; |
| DeclName DM = VD->getFullName(); |
| if (isa<AbstractFunctionDecl>(VD) || isa<SubscriptDecl>(VD)) { |
| if (DM.getBaseName().empty()) { |
| Result.append("_"); |
| } else { |
| Result.append(getEscapedName(DM.getBaseName())); |
| } |
| |
| Result.append("("); |
| for (auto Arg : DM.getArgumentNames()) { |
| Result.append(Arg.empty() ? "_" : Arg.str()); |
| Result.append(":"); |
| } |
| Result.append(")"); |
| return Ctx.buffer(Result.str()); |
| } |
| Result.append(getEscapedName(DM.getBaseName())); |
| return Ctx.buffer(Result.str()); |
| } |
| |
| static bool isFuncThrowing(ValueDecl *VD) { |
| if (auto AF = dyn_cast<AbstractFunctionDecl>(VD)) { |
| return AF->hasThrows(); |
| } |
| return false; |
| } |
| |
| static bool isFuncMutating(ValueDecl *VD) { |
| if (auto AF = dyn_cast<FuncDecl>(VD)) { |
| return AF->isMutating(); |
| } |
| return false; |
| } |
| |
| static Optional<uint8_t> getSelfIndex(ValueDecl *VD) { |
| if (auto AF = dyn_cast<AbstractFunctionDecl>(VD)) { |
| if (AF->isImportAsInstanceMember()) |
| return AF->getSelfIndex(); |
| } |
| return None; |
| } |
| |
| static ReferenceOwnership getReferenceOwnership(ValueDecl *VD) { |
| if (auto OA = VD->getAttrs().getAttribute<ReferenceOwnershipAttr>()) { |
| return OA->get(); |
| } |
| return ReferenceOwnership::Strong; |
| } |
| |
| // Get a requirement with all types canonicalized. |
| Requirement getCanonicalRequirement(Requirement &Req) { |
| auto kind = Req.getKind(); |
| if (kind == RequirementKind::Layout) { |
| return Requirement(kind, Req.getFirstType()->getCanonicalType(), |
| Req.getLayoutConstraint()); |
| } else { |
| return Requirement(kind, Req.getFirstType()->getCanonicalType(), |
| Req.getSecondType()->getCanonicalType()); |
| } |
| } |
| |
| static StringRef printGenericSignature(SDKContext &Ctx, ValueDecl *VD) { |
| llvm::SmallString<32> Result; |
| llvm::raw_svector_ostream OS(Result); |
| if (auto *PD = dyn_cast<ProtocolDecl>(VD)) { |
| if (PD->getRequirementSignature().empty()) |
| return StringRef(); |
| OS << "<"; |
| bool First = true; |
| for (auto Req: PD->getRequirementSignature()) { |
| if (!First) { |
| OS << ", "; |
| } else { |
| First = false; |
| } |
| if (Ctx.checkingABI()) |
| getCanonicalRequirement(Req).print(OS, PrintOptions::printInterface()); |
| else |
| Req.print(OS, PrintOptions::printInterface()); |
| } |
| OS << ">"; |
| return Ctx.buffer(OS.str()); |
| } |
| |
| if (auto *GC = VD->getAsGenericContext()) { |
| if (auto *Sig = GC->getGenericSignature()) { |
| if (Ctx.checkingABI()) |
| Sig->getCanonicalSignature()->print(OS); |
| else |
| Sig->print(OS); |
| return Ctx.buffer(OS.str()); |
| } |
| } |
| return StringRef(); |
| } |
| |
| static Optional<unsigned> getFixedBinaryOrder(ValueDecl *VD) { |
| auto D = VD->getDeclContext()->getAsDecl(); |
| if (!D) |
| return None; |
| |
| if (auto *ED = dyn_cast<EnumDecl>(D)) { |
| auto Check = [](Decl *M) { |
| return isa<EnumElementDecl>(M); |
| }; |
| if (!ED->isResilient() && Check(VD)) { |
| auto Members = ED->getMembers(); |
| auto End = std::find(Members.begin(), Members.end(), VD); |
| assert(End != Members.end()); |
| return std::count_if(Members.begin(), End, Check); |
| } |
| } |
| if (auto *SD = dyn_cast<StructDecl>(D)) { |
| auto Check = [](Decl *M) { |
| if (auto *STD = dyn_cast<AbstractStorageDecl>(M)) { |
| return STD->hasStorage() && !STD->isStatic(); |
| } |
| return false; |
| }; |
| if (!SD->isResilient() && Check(VD)) { |
| auto Members = SD->getMembers(); |
| auto End = std::find(Members.begin(), Members.end(), VD); |
| assert(End != Members.end()); |
| return std::count_if(Members.begin(), End, Check); |
| } |
| } |
| return llvm::None; |
| } |
| |
| SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Type Ty, |
| TypeInitInfo TypeInfo) : |
| Ctx(Ctx), Name(getTypeName(Ctx, Ty, TypeInfo.IsImplicitlyUnwrappedOptional)), |
| PrintedName(getPrintedName(Ctx, Ty, TypeInfo.IsImplicitlyUnwrappedOptional)), |
| TypeInfo(TypeInfo) { |
| if (isFunctionTypeNoEscape(Ty)) |
| TypeAttrs.push_back(TypeAttrKind::TAK_noescape); |
| // If this is a nominal type, get its Usr. |
| if (auto *ND = Ty->getAnyNominal()) { |
| USR = calculateUsr(Ctx, ND); |
| } |
| } |
| |
| SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, ValueDecl *VD) |
| : Ctx(Ctx), |
| Name(VD->hasName() ? getEscapedName(VD->getBaseName()) : Ctx.buffer("_")), |
| PrintedName(getPrintedName(Ctx, VD)), DKind(VD->getKind()), |
| USR(calculateUsr(Ctx, VD)), Location(calculateLocation(Ctx, VD)), |
| ModuleName(VD->getModuleContext()->getName().str()), |
| IsImplicit(VD->isImplicit()), |
| IsThrowing(isFuncThrowing(VD)), IsMutating(isFuncMutating(VD)), |
| IsStatic(VD->isStatic()), |
| IsDeprecated(VD->getAttrs().getDeprecated(VD->getASTContext())), |
| SelfIndex(getSelfIndex(VD)), FixedBinaryOrder(getFixedBinaryOrder(VD)), |
| ReferenceOwnership(getReferenceOwnership(VD)), |
| GenericSig(printGenericSignature(Ctx, VD)) { |
| |
| // Calculate usr for its super class. |
| if (auto *CD = dyn_cast_or_null<ClassDecl>(VD)) { |
| if (auto *Super = CD->getSuperclassDecl()) |
| SuperclassUsr = calculateUsr(Ctx, Super); |
| } |
| |
| // Capture all attributes. |
| auto AllAttrs = VD->getAttrs(); |
| std::transform(AllAttrs.begin(), AllAttrs.end(), std::back_inserter(DeclAttrs), |
| [](DeclAttribute *attr) { return attr->getKind(); }); |
| |
| // Get all protocol names this type decl conforms to. |
| if (auto *NTD = dyn_cast<NominalTypeDecl>(VD)) { |
| for (auto *P: NTD->getAllProtocols()) { |
| ConformingProtocols.push_back(P->getName().str()); |
| } |
| } |
| |
| // Get enum raw type name if this is an enum. |
| if (auto *ED = dyn_cast<EnumDecl>(VD)) { |
| if (auto RT = ED->getRawType()) { |
| if (auto *D = RT->getNominalOrBoundGenericNominal()) { |
| EnumRawTypeName = D->getName().str(); |
| } |
| } |
| } |
| |
| // Record whether a subscript has getter/setter. |
| if (auto *SD = dyn_cast<SubscriptDecl>(VD)) { |
| HasSetter = SD->getSetter(); |
| } |
| } |
| |
| SDKNode *SDKNodeInitInfo::createSDKNode(SDKNodeKind Kind) { |
| switch(Kind) { |
| #define NODE_KIND(X, NAME) \ |
| case SDKNodeKind::X: \ |
| return static_cast<SDKNode*>(new (Ctx.allocator().Allocate<SDKNode##X>()) \ |
| SDKNode##X(*this)); \ |
| break; |
| #include "swift/IDE/DigesterEnums.def" |
| } |
| } |
| |
| // Recursively construct a node that represents a type, for instance, |
| // representing the return value type of a function decl. |
| static SDKNode *constructTypeNode(SDKContext &Ctx, Type T, |
| TypeInitInfo InitInfo = TypeInitInfo()) { |
| if (Ctx.checkingABI()) { |
| T = T->getCanonicalType(); |
| } |
| SDKNode* Root = SDKNodeInitInfo(Ctx, T, InitInfo) |
| .createSDKNode(SDKNodeKind::TypeNominal); |
| |
| if (auto NAT = dyn_cast<NameAliasType>(T.getPointer())) { |
| SDKNode* Root = SDKNodeInitInfo(Ctx, T).createSDKNode(SDKNodeKind::TypeAlias); |
| Root->addChild(constructTypeNode(Ctx, NAT->getCanonicalType())); |
| return Root; |
| } |
| |
| if (auto Fun = T->getAs<AnyFunctionType>()) { |
| SDKNode* Root = SDKNodeInitInfo(Ctx, T).createSDKNode(SDKNodeKind::TypeFunc); |
| |
| // Still, return type first |
| Root->addChild(constructTypeNode(Ctx, Fun->getResult())); |
| Root->addChild(constructTypeNode(Ctx, Fun->getInput())); |
| return Root; |
| } |
| |
| // Keep paren type as a stand-alone level. |
| if (auto *PT = dyn_cast<ParenType>(T.getPointer())) { |
| Root->addChild(constructTypeNode(Ctx, PT->getSinglyDesugaredType())); |
| return Root; |
| } |
| |
| // Handle the case where Type has sub-types. |
| if (auto BGT = T->getAs<BoundGenericType>()) { |
| for (auto Arg : BGT->getGenericArgs()) { |
| Root->addChild(constructTypeNode(Ctx, Arg)); |
| } |
| } else if (auto Tup = T->getAs<TupleType>()) { |
| for (auto Elt : Tup->getElementTypes()) |
| Root->addChild(constructTypeNode(Ctx, Elt)); |
| } else if (auto MTT = T->getAs<AnyMetatypeType>()) { |
| Root->addChild(constructTypeNode(Ctx, MTT->getInstanceType())); |
| } else if (auto ATT = T->getAs<ArchetypeType>()) { |
| for (auto Pro : ATT->getConformsTo()) { |
| Root->addChild(constructTypeNode(Ctx, Pro->getDeclaredType())); |
| } |
| } |
| return Root; |
| } |
| |
| static std::vector<SDKNode*> |
| createParameterNodes(SDKContext &Ctx, ParameterList *PL) { |
| std::vector<SDKNode*> Result; |
| for (auto param: *PL) { |
| TypeInitInfo TypeInfo; |
| TypeInfo.IsImplicitlyUnwrappedOptional = param->getAttrs(). |
| hasAttribute<ImplicitlyUnwrappedOptionalAttr>(); |
| TypeInfo.hasDefaultArgument = param->getDefaultArgumentKind() != |
| DefaultArgumentKind::None; |
| Result.push_back(constructTypeNode(Ctx, param->getInterfaceType(), |
| TypeInfo)); |
| } |
| return Result; |
| } |
| |
| // Construct a node for a function decl. The first child of the function decl |
| // is guaranteed to be the return value type of this function. |
| // We sometimes skip the first parameter because it can be metatype of dynamic |
| // this if the function is a member function. |
| static SDKNode *constructFunctionNode(SDKContext &Ctx, FuncDecl* FD, |
| SDKNodeKind Kind) { |
| auto Func = SDKNodeInitInfo(Ctx, FD).createSDKNode(Kind); |
| TypeInitInfo TypeInfo; |
| TypeInfo.IsImplicitlyUnwrappedOptional = FD->getAttrs(). |
| hasAttribute<ImplicitlyUnwrappedOptionalAttr>(); |
| Func->addChild(constructTypeNode(Ctx, FD->getResultInterfaceType(), TypeInfo)); |
| for (auto *Node : createParameterNodes(Ctx, FD->getParameters())) |
| Func->addChild(Node); |
| return Func; |
| } |
| |
| static SDKNode* constructInitNode(SDKContext &Ctx, ConstructorDecl *CD) { |
| auto Func = SDKNodeInitInfo(Ctx, CD).createSDKNode(SDKNodeKind::DeclConstructor); |
| Func->addChild(constructTypeNode(Ctx, CD->getResultInterfaceType())); |
| for (auto *Node : createParameterNodes(Ctx, CD->getParameters())) |
| Func->addChild(Node); |
| return Func; |
| } |
| |
| static bool shouldIgnore(Decl *D, const Decl* Parent, SDKContext &Ctx) { |
| if (D->isPrivateStdlibDecl(false)) |
| return true; |
| if (AvailableAttr::isUnavailable(D)) |
| return true; |
| if (isa<ConstructorDecl>(D)) |
| return false; |
| if (isa<OperatorDecl>(D)) |
| return true; |
| if (auto VD = dyn_cast<ValueDecl>(D)) { |
| if (VD->isOperator()) |
| return true; |
| if (VD->getBaseName().empty()) |
| return true; |
| switch (VD->getFormalAccess()) { |
| case AccessLevel::Internal: |
| case AccessLevel::Private: |
| case AccessLevel::FilePrivate: |
| // Private vars with fixed binary orders can have ABI-impact, so we should |
| // whitelist them if we're checking ABI. |
| if (Ctx.checkingABI() && getFixedBinaryOrder(VD).hasValue()) |
| break; |
| return true; |
| case AccessLevel::Public: |
| case AccessLevel::Open: |
| break; |
| } |
| } |
| |
| if (auto *ClangD = D->getClangDecl()) { |
| if (isa<clang::ObjCIvarDecl>(ClangD)) |
| return true; |
| if (isa<clang::FieldDecl>(ClangD)) |
| return true; |
| if (ClangD->hasAttr<clang::SwiftPrivateAttr>()) |
| return true; |
| |
| // If this decl is a synthesized member from a conformed clang protocol, we |
| // should ignore this member to reduce redundancy. |
| if (Parent && |
| !isa<swift::ProtocolDecl>(Parent) && |
| isa<clang::ObjCProtocolDecl>(ClangD->getDeclContext())) |
| return true; |
| } |
| return false; |
| } |
| |
| static void addMembersToRoot(SDKContext &Ctx, SDKNode *Root, |
| IterableDeclContext *Context, |
| std::set<ExtensionDecl*> &HandledExts); |
| |
| static SDKNode *constructTypeDeclNode(SDKContext &Ctx, NominalTypeDecl *NTD, |
| std::set<ExtensionDecl*> &HandledExts) { |
| auto TypeNode = SDKNodeInitInfo(Ctx, NTD).createSDKNode(SDKNodeKind::DeclType); |
| addMembersToRoot(Ctx, TypeNode, NTD, HandledExts); |
| for (auto Ext : NTD->getExtensions()) { |
| HandledExts.insert(Ext); |
| addMembersToRoot(Ctx, TypeNode, Ext, HandledExts); |
| } |
| return TypeNode; |
| } |
| |
| /// Create a node for stand-alone extensions. In the sdk dump, we don't have |
| /// a specific node for extension. Members in extensions are inlined to the |
| /// extended types. If the extended types are from a different module, we have to |
| /// synthesize this type node to include those extension members, since these |
| /// extension members are legit members of the module. |
| static SDKNode *constructExternalExtensionNode(SDKContext &Ctx, SDKNode *Root, |
| NominalTypeDecl *NTD, |
| ArrayRef<ExtensionDecl*> AllExts, |
| std::set<ExtensionDecl*> &HandledExts) { |
| auto *TypeNode = SDKNodeInitInfo(Ctx, NTD).createSDKNode(SDKNodeKind::DeclType); |
| |
| // The members of the extensions are the only members of this synthesized type. |
| for (auto *Ext: AllExts) { |
| HandledExts.insert(Ext); |
| addMembersToRoot(Ctx, TypeNode, Ext, HandledExts); |
| } |
| return TypeNode; |
| } |
| |
| static SDKNode *constructVarNode(SDKContext &Ctx, ValueDecl *VD) { |
| auto Var = SDKNodeInitInfo(Ctx, VD).createSDKNode(SDKNodeKind::DeclVar); |
| TypeInitInfo TypeInfo; |
| TypeInfo.IsImplicitlyUnwrappedOptional = VD->getAttrs(). |
| hasAttribute<ImplicitlyUnwrappedOptionalAttr>(); |
| Var->addChild(constructTypeNode(Ctx, VD->getInterfaceType(), TypeInfo)); |
| if (auto VAD = dyn_cast<AbstractStorageDecl>(VD)) { |
| if (auto Getter = VAD->getGetter()) |
| Var->addChild(constructFunctionNode(Ctx, Getter, SDKNodeKind::DeclGetter)); |
| if (auto Setter = VAD->getSetter()) { |
| if (Setter->getFormalAccess() > AccessLevel::Internal) |
| Var->addChild(constructFunctionNode(Ctx, Setter, SDKNodeKind::DeclSetter)); |
| } |
| } |
| return Var; |
| } |
| |
| static SDKNode *constructTypeAliasNode(SDKContext &Ctx,TypeAliasDecl *TAD) { |
| auto Alias = SDKNodeInitInfo(Ctx, TAD).createSDKNode(SDKNodeKind::DeclTypeAlias); |
| Alias->addChild(constructTypeNode(Ctx, TAD->getUnderlyingTypeLoc().getType())); |
| return Alias; |
| } |
| |
| static SDKNode *constructAssociatedTypeNode(SDKContext &Ctx, |
| AssociatedTypeDecl *ATD) { |
| auto Asso = SDKNodeInitInfo(Ctx, ATD). |
| createSDKNode(SDKNodeKind::DeclAssociatedType); |
| if (auto DT = ATD->getDefaultDefinitionType()) { |
| Asso->addChild(constructTypeNode(Ctx, DT)); |
| } |
| return Asso; |
| } |
| |
| static SDKNode *constructSubscriptDeclNode(SDKContext &Ctx, SubscriptDecl *SD) { |
| auto Subs = SDKNodeInitInfo(Ctx, SD).createSDKNode(SDKNodeKind::DeclSubscript); |
| Subs->addChild(constructTypeNode(Ctx, SD->getElementInterfaceType())); |
| for (auto *Node: createParameterNodes(Ctx, SD->getIndices())) |
| Subs->addChild(Node); |
| return Subs; |
| } |
| |
| static void addMembersToRoot(SDKContext &Ctx, SDKNode *Root, |
| IterableDeclContext *Context, |
| std::set<ExtensionDecl*> &HandledExts) { |
| for (auto *Member : Context->getMembers()) { |
| if (shouldIgnore(Member, Context->getDecl(), Ctx)) |
| continue; |
| if (auto Func = dyn_cast<FuncDecl>(Member)) { |
| Root->addChild(constructFunctionNode(Ctx, Func, SDKNodeKind::DeclFunction)); |
| } else if (auto CD = dyn_cast<ConstructorDecl>(Member)) { |
| Root->addChild(constructInitNode(Ctx, CD)); |
| } else if (auto VD = dyn_cast<VarDecl>(Member)) { |
| Root->addChild(constructVarNode(Ctx, VD)); |
| } else if (auto TAD = dyn_cast<TypeAliasDecl>(Member)) { |
| Root->addChild(constructTypeAliasNode(Ctx, TAD)); |
| } else if (auto EED = dyn_cast<EnumElementDecl>(Member)) { |
| Root->addChild(constructVarNode(Ctx, EED)); |
| } else if (auto NTD = dyn_cast<NominalTypeDecl>(Member)) { |
| Root->addChild(constructTypeDeclNode(Ctx, NTD, HandledExts)); |
| } else if (auto ATD = dyn_cast<AssociatedTypeDecl>(Member)) { |
| Root->addChild(constructAssociatedTypeNode(Ctx, ATD)); |
| } else if (auto SD = dyn_cast<SubscriptDecl>(Member)) { |
| Root->addChild(constructSubscriptDeclNode(Ctx, SD)); |
| } else if (isa<PatternBindingDecl>(Member)) { |
| // All containing variables should have been handled. |
| } else if (isa<DestructorDecl>(Member)) { |
| // deinit has no impact. |
| } else { |
| llvm_unreachable("unhandled member decl kind."); |
| } |
| } |
| } |
| |
| void SwiftDeclCollector::printTopLevelNames() { |
| for (auto &Node : RootNode->getChildren()) { |
| llvm::outs() << Node->getKind() << ": " << Node->getName() << '\n'; |
| } |
| } |
| |
| void SwiftDeclCollector::lookupVisibleDecls(ArrayRef<ModuleDecl *> Modules) { |
| for (auto M: Modules) { |
| llvm::SmallVector<Decl*, 512> Decls; |
| M->getDisplayDecls(Decls); |
| for (auto D : Decls) { |
| if (shouldIgnore(D, nullptr, Ctx)) |
| continue; |
| if (KnownDecls.count(D)) |
| continue; |
| KnownDecls.insert(D); |
| if (auto VD = dyn_cast<ValueDecl>(D)) |
| foundDecl(VD, DeclVisibilityKind::DynamicLookup); |
| } |
| } |
| |
| // Now sort the macros before processing so that we can have deterministic |
| // output. |
| llvm::array_pod_sort(ClangMacros.begin(), ClangMacros.end(), |
| [](ValueDecl * const *lhs, |
| ValueDecl * const *rhs) -> int { |
| return (*lhs)->getBaseName().userFacingName().compare( |
| (*rhs)->getBaseName().userFacingName()); |
| }); |
| |
| for (auto *VD : ClangMacros) |
| processDecl(VD); |
| |
| // Collect extensions to types from other modules and synthesize type nodes |
| // for them. |
| llvm::MapVector<NominalTypeDecl*, llvm::SmallVector<ExtensionDecl*, 4>> ExtensionMap; |
| for (auto *D: KnownDecls) { |
| if (auto *Ext = dyn_cast<ExtensionDecl>(D)) { |
| if (HandledExtensions.find(Ext) == HandledExtensions.end()) { |
| ExtensionMap[Ext->getExtendedNominal()].push_back(Ext); |
| } |
| } |
| } |
| for (auto Pair: ExtensionMap) { |
| RootNode->addChild(constructExternalExtensionNode(Ctx, RootNode, |
| Pair.first, Pair.second, HandledExtensions)); |
| } |
| } |
| |
| void SwiftDeclCollector::processDecl(ValueDecl *VD) { |
| if (auto FD = dyn_cast<FuncDecl>(VD)) { |
| RootNode->addChild(constructFunctionNode(Ctx, FD, SDKNodeKind::DeclFunction)); |
| } else if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) { |
| RootNode->addChild(constructTypeDeclNode(Ctx, NTD, HandledExtensions)); |
| } |
| if (auto VAD = dyn_cast<VarDecl>(VD)) { |
| RootNode->addChild(constructVarNode(Ctx, VAD)); |
| } |
| if (auto TAD = dyn_cast<TypeAliasDecl>(VD)) { |
| RootNode->addChild(constructTypeAliasNode(Ctx, TAD)); |
| } |
| } |
| |
| void SwiftDeclCollector::foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) { |
| if (VD->getClangMacro()) { |
| // Collect macros, we will sort them afterwards. |
| ClangMacros.push_back(VD); |
| return; |
| } |
| |
| processDecl(VD); |
| } |
| |
| namespace swift { |
| namespace json { |
| // In the namespace of swift::json, we define several functions so that the |
| // JSON serializer will know how to interpret and dump types defined in this |
| // file. |
| template<> |
| struct ScalarEnumerationTraits<TypeAttrKind> { |
| static void enumeration(Output &out, TypeAttrKind &value) { |
| #define TYPE_ATTR(X) out.enumCase(value, #X, TypeAttrKind::TAK_##X); |
| #include "swift/AST/Attr.def" |
| } |
| }; |
| |
| template<> |
| struct ScalarEnumerationTraits<DeclAttrKind> { |
| static void enumeration(Output &out, DeclAttrKind &value) { |
| #define DECL_ATTR(_, Name, ...) out.enumCase(value, #Name, DeclAttrKind::DAK_##Name); |
| #include "swift/AST/Attr.def" |
| } |
| }; |
| |
| template<> |
| struct ScalarEnumerationTraits<DeclKind> { |
| static void enumeration(Output &out, DeclKind &value) { |
| #define DECL(X, PARENT) out.enumCase(value, #X, DeclKind::X); |
| #include "swift/AST/DeclNodes.def" |
| } |
| }; |
| |
| template<> |
| struct ObjectTraits<SDKNode *> { |
| static void mapping(Output &out, SDKNode *&value) { |
| auto Kind = value->getKind(); |
| auto Name = value->getName(); |
| auto PrintedName = value->getPrintedName(); |
| auto &Ctx = value->getSDKContext(); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_kind).data(), Kind); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_name).data(), Name); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_printedName).data(), |
| PrintedName); |
| |
| if (auto D = dyn_cast<SDKNodeDecl>(value)) { |
| DeclKind DK = D->getDeclKind(); |
| StringRef Usr = D->getUsr(); |
| StringRef Location = D->getLocation(); |
| StringRef ModuleName = D->getModuleName(); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_declKind).data(), DK); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_usr).data(), Usr); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_location).data(), Location); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_moduleName).data(), |
| ModuleName); |
| auto GSig = D->getGenericSignature(); |
| if (!GSig.empty()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_genericSig), GSig); |
| |
| if (auto isStatic = D->isStatic()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_static).data(), isStatic); |
| if (bool isDeprecated = D->isDeprecated()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_deprecated).data(), |
| isDeprecated); |
| if (bool isImplicit = D->isImplicit()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_implicit).data(), |
| isImplicit); |
| if (auto V = dyn_cast<SDKNodeDeclVar>(value)) { |
| if (V->hasFixedBinaryOrder()) { |
| auto Order = V->getFixedBinaryOrder(); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_fixedbinaryorder).data(), |
| Order); |
| } |
| } |
| if (auto F = dyn_cast<SDKNodeDeclAbstractFunc>(value)) { |
| if (bool isThrowing = F->isThrowing()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_throwing).data(), |
| isThrowing); |
| if (bool isMutating = F->isMutating()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_mutating).data(), |
| isMutating); |
| if (F->hasSelfIndex()) { |
| auto Index = F->getSelfIndex(); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_selfIndex).data(), |
| Index); |
| } |
| if (auto S = dyn_cast<SDKNodeDeclSubscript>(value)) { |
| if (bool hasSetter = S->hasSetter()) { |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_hasSetter).data(), |
| hasSetter); |
| } |
| } |
| } |
| if (auto *TD = dyn_cast<SDKNodeDeclType>(value)) { |
| auto Super = TD->getSuperClassUsr(); |
| if (!Super.empty()) { |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_superclassUsr).data(), |
| Super); |
| } |
| auto Pros = TD->getAllProtocols(); |
| if (!Pros.empty()) { |
| out.mapRequired(getKeyContent(Ctx, |
| KeyKind::KK_conformingProtocols).data(), |
| Pros); |
| } |
| |
| auto RawTypeName = TD->isEnum() ? TD->getEnumRawTypeName() : StringRef(); |
| if (!RawTypeName.empty()) { |
| out.mapRequired(getKeyContent(Ctx, |
| KeyKind::KK_enumRawTypeName).data(), |
| RawTypeName); |
| } |
| |
| } |
| auto Attributes = D->getDeclAttributes(); |
| if (!Attributes.empty()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_declAttributes).data(), |
| Attributes); |
| // Strong reference is implied, no need for serialization. |
| if (D->getReferenceOwnership() != ReferenceOwnership::Strong) { |
| uint8_t Raw = uint8_t(D->getReferenceOwnership()); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_ownership).data(), Raw); |
| } |
| } else if (auto T = dyn_cast<SDKNodeType>(value)) { |
| auto Attributes = T->getTypeAttributes(); |
| if (!Attributes.empty()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_typeAttributes).data(), |
| Attributes); |
| if (bool HasDefault = T->hasDefaultArgument()) { |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_hasDefaultArg).data(), |
| HasDefault); |
| } |
| // Serialize nominal type's USR. |
| if (auto NT = dyn_cast<SDKNodeTypeNominal>(value)) { |
| auto Usr = NT->getUsr(); |
| if (!Usr.empty()) |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_usr).data(), Usr); |
| } |
| } |
| if (!value->isLeaf()) { |
| ArrayRef<SDKNode *> Children = value->getChildren(); |
| out.mapRequired(getKeyContent(Ctx, KeyKind::KK_children).data(), Children); |
| } |
| } |
| }; |
| |
| template<> |
| struct ArrayTraits<ArrayRef<SDKNode*>> { |
| static size_t size(Output &out, ArrayRef<SDKNode *> &seq) { |
| return seq.size(); |
| } |
| static SDKNode *&element(Output &, ArrayRef<SDKNode *> &seq, |
| size_t index) { |
| return const_cast<SDKNode *&>(seq[index]); |
| } |
| }; |
| |
| template<> |
| struct ArrayTraits<ArrayRef<TypeAttrKind>> { |
| static size_t size(Output &out, ArrayRef<TypeAttrKind> &seq) { |
| return seq.size(); |
| } |
| static TypeAttrKind& element(Output &, ArrayRef<TypeAttrKind> &seq, |
| size_t index) { |
| return const_cast<TypeAttrKind&>(seq[index]); |
| } |
| }; |
| |
| template<> |
| struct ArrayTraits<ArrayRef<DeclAttrKind>> { |
| static size_t size(Output &out, ArrayRef<DeclAttrKind> &seq) { |
| return seq.size(); |
| } |
| static DeclAttrKind& element(Output &, ArrayRef<DeclAttrKind> &seq, |
| size_t index) { |
| return const_cast<DeclAttrKind&>(seq[index]); |
| } |
| }; |
| template<> |
| struct ArrayTraits<ArrayRef<StringRef>> { |
| static size_t size(Output &out, ArrayRef<StringRef> &seq) { |
| return seq.size(); |
| } |
| static StringRef& element(Output &, ArrayRef<StringRef> &seq, |
| size_t index) { |
| return const_cast<StringRef&>(seq[index]); |
| } |
| }; |
| } // namespace json |
| } // namespace swift |
| |
| namespace {// Anonymous namespace. |
| // Serialize a forest of SDKNode trees to the given stream. |
| static void emitSDKNodeRoot(llvm::raw_ostream &os, SDKNode *&Root) { |
| json::Output yout(os); |
| yout << Root; |
| } |
| |
| // Deserialize an SDKNode tree. |
| std::pair<std::unique_ptr<llvm::MemoryBuffer>, SDKNode*> |
| static parseJsonEmit(SDKContext &Ctx, StringRef FileName) { |
| namespace yaml = llvm::yaml; |
| |
| // Load the input file. |
| llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr = |
| vfs::getFileOrSTDIN(*Ctx.getSourceMgr().getFileSystem(), FileName); |
| if (!FileBufOrErr) { |
| llvm_unreachable("Failed to read JSON file"); |
| } |
| StringRef Buffer = FileBufOrErr->get()->getBuffer(); |
| yaml::Stream Stream(llvm::MemoryBufferRef(Buffer, FileName), |
| Ctx.getSourceMgr().getLLVMSourceMgr()); |
| SDKNode *Result = nullptr; |
| for (auto DI = Stream.begin(); DI != Stream.end(); ++ DI) { |
| assert(DI != Stream.end() && "Failed to read a document"); |
| yaml::Node *N = DI->getRoot(); |
| assert(N && "Failed to find a root"); |
| Result = SDKNode::constructSDKNode(Ctx, cast<yaml::MappingNode>(N)); |
| if (Ctx.getDiags().hadAnyError()) |
| exit(1); |
| } |
| return {std::move(FileBufOrErr.get()), Result}; |
| } |
| |
| static std::string getDumpFilePath(StringRef OutputDir, StringRef FileName) { |
| std::string Path = OutputDir; |
| Path += "/"; |
| Path += FileName; |
| int Suffix = 0; |
| auto ConstructPath = [&]() { |
| return Path + (Suffix == 0 ? "" : std::to_string(Suffix)) + ".js"; |
| }; |
| for (; fs::exists(ConstructPath()); Suffix ++); |
| return ConstructPath(); |
| } |
| } // End of anonymous namespace |
| |
| // Construct all roots vector from a given file where a forest was |
| // previously dumped. |
| void SwiftDeclCollector::deSerialize(StringRef Filename) { |
| auto Pair = parseJsonEmit(Ctx, Filename); |
| OwnedBuffers.push_back(std::move(Pair.first)); |
| RootNode = std::move(Pair.second); |
| } |
| |
| // Serialize the content of all roots to a given file using JSON format. |
| void SwiftDeclCollector::serialize(StringRef Filename) { |
| std::error_code EC; |
| llvm::raw_fd_ostream fs(Filename, EC, llvm::sys::fs::F_None); |
| emitSDKNodeRoot(fs, RootNode); |
| } |
| |
| int swift::ide::api::dumpSwiftModules(const CompilerInvocation &InitInvok, |
| const llvm::StringSet<> &ModuleNames, |
| StringRef OutputDir, |
| const std::vector<std::string> PrintApis, |
| CheckerOptions Opts) { |
| if (!fs::exists(OutputDir)) { |
| llvm::errs() << "Output directory '" << OutputDir << "' does not exist.\n"; |
| return 1; |
| } |
| |
| std::vector<ModuleDecl*> Modules; |
| CompilerInvocation Invocation(InitInvok); |
| CompilerInstance CI; |
| // Display diagnostics to stderr. |
| PrintingDiagnosticConsumer PrintDiags; |
| CI.addDiagnosticConsumer(&PrintDiags); |
| if (CI.setup(Invocation)) { |
| llvm::errs() << "Failed to setup the compiler instance\n"; |
| return 1; |
| } |
| |
| auto &Context = CI.getASTContext(); |
| |
| for (auto &Entry : ModuleNames) { |
| StringRef Name = Entry.first(); |
| if (Opts.Verbose) |
| llvm::errs() << "Loading module: " << Name << "...\n"; |
| auto *M = Context.getModuleByName(Name); |
| if (!M) { |
| if (Opts.Verbose) |
| llvm::errs() << "Failed to load module: " << Name << '\n'; |
| if (Opts.AbortOnModuleLoadFailure) |
| return 1; |
| } |
| Modules.push_back(M); |
| } |
| |
| PrintingDiagnosticConsumer PDC; |
| SDKContext Ctx(Opts); |
| Ctx.getDiags().addConsumer(PDC); |
| |
| for (auto M : Modules) { |
| SwiftDeclCollector Collector(Ctx); |
| SmallVector<Decl*, 256> Decls; |
| M->getTopLevelDecls(Decls); |
| for (auto D : Decls) { |
| if (auto VD = dyn_cast<ValueDecl>(D)) |
| Collector.foundDecl(VD, DeclVisibilityKind::VisibleAtTopLevel); |
| } |
| std::string Path = getDumpFilePath(OutputDir, M->getName().str()); |
| Collector.serialize(Path); |
| if (Opts.Verbose) |
| llvm::errs() << "Dumped to "<< Path << "\n"; |
| } |
| return 0; |
| } |
| |
| int swift::ide::api::dumpSDKContent(const CompilerInvocation &InitInvok, |
| const llvm::StringSet<> &ModuleNames, |
| StringRef OutputFile, CheckerOptions Opts) { |
| CompilerInvocation Invocation(InitInvok); |
| |
| CompilerInstance CI; |
| // Display diagnostics to stderr. |
| PrintingDiagnosticConsumer PrintDiags; |
| CI.addDiagnosticConsumer(&PrintDiags); |
| if (CI.setup(Invocation)) { |
| llvm::errs() << "Failed to setup the compiler instance\n"; |
| return 1; |
| } |
| |
| auto &Ctx = CI.getASTContext(); |
| |
| |
| // Load standard library so that Clang importer can use it. |
| auto *Stdlib = Ctx.getStdlibModule(/*loadIfAbsent=*/true); |
| if (!Stdlib) { |
| llvm::errs() << "Failed to load Swift stdlib\n"; |
| return 1; |
| } |
| |
| std::vector<ModuleDecl *> Modules; |
| for (auto &Entry : ModuleNames) { |
| StringRef Name = Entry.getKey(); |
| if (Opts.Verbose) |
| llvm::errs() << "Loading module: " << Name << "...\n"; |
| auto *M = Ctx.getModuleByName(Name); |
| if (!M) { |
| llvm::errs() << "Failed to load module: " << Name << '\n'; |
| if (Opts.AbortOnModuleLoadFailure) |
| return 1; |
| } else { |
| Modules.push_back(M); |
| } |
| } |
| if (Opts.Verbose) |
| llvm::errs() << "Scanning symbols...\n"; |
| SDKContext SDKCtx(Opts); |
| SwiftDeclCollector Collector(SDKCtx); |
| Collector.lookupVisibleDecls(Modules); |
| if (Opts.Verbose) |
| llvm::errs() << "Dumping SDK...\n"; |
| Collector.serialize(OutputFile); |
| if (Opts.Verbose) |
| llvm::errs() << "Dumped to "<< OutputFile << "\n"; |
| return 0; |
| } |
| |
| int swift::ide::api::deserializeSDKDump(StringRef dumpPath, StringRef OutputPath, |
| CheckerOptions Opts) { |
| std::error_code EC; |
| llvm::raw_fd_ostream FS(OutputPath, EC, llvm::sys::fs::F_None); |
| if (!fs::exists(dumpPath)) { |
| llvm::errs() << dumpPath << " does not exist\n"; |
| return 1; |
| } |
| PrintingDiagnosticConsumer PDC; |
| SDKContext Ctx(Opts); |
| Ctx.getDiags().addConsumer(PDC); |
| |
| SwiftDeclCollector Collector(Ctx); |
| Collector.deSerialize(dumpPath); |
| Collector.serialize(OutputPath); |
| return 0; |
| } |
| |
| int swift::ide::api::findDeclUsr(StringRef dumpPath, CheckerOptions Opts) { |
| std::error_code EC; |
| if (!fs::exists(dumpPath)) { |
| llvm::errs() << dumpPath << " does not exist\n"; |
| return 1; |
| } |
| PrintingDiagnosticConsumer PDC; |
| SDKContext Ctx(Opts); |
| Ctx.getDiags().addConsumer(PDC); |
| |
| SwiftDeclCollector Collector(Ctx); |
| Collector.deSerialize(dumpPath); |
| struct FinderByLocation: SDKNodeVisitor { |
| StringRef Location; |
| FinderByLocation(StringRef Location): Location(Location) {} |
| void visit(SDKNode* Node) override { |
| if (auto *D = dyn_cast<SDKNodeDecl>(Node)) { |
| if (D->getLocation().find(Location) != StringRef::npos && |
| !D->getUsr().empty()) { |
| llvm::outs() << D->getFullyQualifiedName() << ": " << D->getUsr() << "\n"; |
| } |
| } |
| } |
| }; |
| if (!Opts.LocationFilter.empty()) { |
| FinderByLocation Finder(Opts.LocationFilter); |
| Collector.visitAllRoots(Finder); |
| } |
| return 0; |
| } |