//===--- ModuleAnaluzerNodes.h - Nodes for API differ tool ---------------====// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Describing nodes from a swiftmodule file to detect ABI/API breakages. // //===----------------------------------------------------------------------===// #ifndef __SWIFT_ABI_DIGESTER_MODULE_NODES_H__ #define __SWIFT_ABI_DIGESTER_MODULE_NODES_H__ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/YAMLTraits.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/NameLookup.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/USRGeneration.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/DiagnosticsModuleDiffer.h" #include "swift/Basic/ColorUtils.h" #include "swift/Basic/JSONSerialization.h" #include "swift/Basic/LLVMInitialize.h" #include "swift/Basic/STLExtras.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/Frontend/Frontend.h" #include "swift/Frontend/PrintingDiagnosticConsumer.h" #include "swift/IDE/Utils.h" #include "swift/IDE/APIDigesterData.h" #include namespace swift { namespace json { class Output; } namespace ide { namespace api { class SDKNode; typedef SDKNode* NodePtr; typedef std::map ParentMap; typedef std::map NodeMap; typedef std::vector NodeVector; typedef std::vector DiffVector; typedef std::vector TypeMemberDiffVector; typedef llvm::MapVector NodePairVector; // The interface used to visit the SDK tree. class SDKNodeVisitor { friend SDKNode; protected: NodeVector Ancestors; virtual void visit(NodePtr Node) = 0; NodePtr parent() { if (Ancestors.empty()) return nullptr; return Ancestors.back(); } int depth() { return Ancestors.size() + 1; } public: virtual ~SDKNodeVisitor() = default; }; enum class NodeMatchReason: uint8_t { // Two nodes are matched because they're both roots. Root, // The first node is missing. Added, // The second node is missing. Removed, // The nodes are considered a pair becuase they have same/similar name. Name, // The nodes are matched because they're in the same order, e.g. ith child of // a type declaration. Sequential, // The first node is a function and it chanaged to a propery as the second // node. FuncToProperty, // The first node is a global variable and the second node is an enum element. ModernizeEnum, // The first node is a type declaration and the second node is a type alias // of another type declaration. TypeToTypeAlias, }; // This map keeps track of updated nodes; thus we can conveniently find out what // is the counterpart of a node before or after being updated. class UpdatedNodesMap { NodePairVector MapImpl; UpdatedNodesMap(const UpdatedNodesMap& that) = delete; public: UpdatedNodesMap() = default; NodePtr findUpdateCounterpart(const SDKNode *Node) const; void insert(NodePtr Left, NodePtr Right) { assert(Left && Right && "Not update operation."); MapImpl.insert({Left, Right}); } }; // Describing some attributes with ABI/API impact. The addition or removal of these // attributes is considerred breakage. struct BreakingAttributeInfo { const DeclAttrKind Kind; const StringRef Content; }; struct CheckerOptions { bool AvoidLocation; bool ABI; bool Verbose; bool AbortOnModuleLoadFailure; bool PrintModule; bool SwiftOnly; StringRef LocationFilter; }; class SDKContext { llvm::StringSet<> TextData; llvm::BumpPtrAllocator Allocator; SourceManager SourceMgr; DiagnosticEngine Diags; UpdatedNodesMap UpdateMap; NodeMap TypeAliasUpdateMap; NodeMap RevertTypeAliasUpdateMap; TypeMemberDiffVector TypeMemberDiffs; CheckerOptions Opts; std::vector BreakingAttrs; /// This is to cache the equal comparison results between nodes. llvm::DenseMap> EqualCache; public: SDKContext(CheckerOptions Options); llvm::BumpPtrAllocator &allocator() { return Allocator; } StringRef buffer(StringRef Text) { return TextData.insert(Text).first->getKey(); } UpdatedNodesMap &getNodeUpdateMap() { return UpdateMap; } NodeMap &getTypeAliasUpdateMap() { return TypeAliasUpdateMap; } NodeMap &getRevertTypeAliasUpdateMap() { return RevertTypeAliasUpdateMap; } TypeMemberDiffVector &getTypeMemberDiffs() { return TypeMemberDiffs; } SourceManager &getSourceMgr() { return SourceMgr; } DiagnosticEngine &getDiags() { return Diags; } bool isEqual(const SDKNode &Left, const SDKNode &Right); bool checkingABI() const { return Opts.ABI; } AccessLevel getAccessLevel(const ValueDecl *VD) const; const CheckerOptions &getOpts() const { return Opts; } bool shouldIgnore(Decl *D, const Decl* Parent = nullptr) const; ArrayRef getBreakingAttributeInfo() const { return BreakingAttrs; } Optional getFixedBinaryOrder(ValueDecl *VD) const; template void diagnose(YAMLNodeTy node, Diag ID, typename detail::PassArgument::type... args) { auto smRange = node->getSourceRange(); auto range = SourceRange(SourceLoc(smRange.Start), SourceLoc(smRange.End)); Diags.diagnose(range.Start, ID, std::forward(args)...) .highlight(range); } }; enum class KnownTypeKind: uint8_t { #define KNOWN_TYPE(NAME) NAME, #include "swift/IDE/DigesterEnums.def" Unknown, }; enum class KnownProtocolKind: uint8_t { #define KNOWN_PROTOCOL(NAME) NAME, #include "swift/IDE/DigesterEnums.def" }; class SDKNodeRoot; class SDKNodeDeclGetter; class SDKNodeDeclSetter; struct SDKNodeInitInfo; class SDKNode { typedef std::vector::iterator ChildIt; protected: SDKContext &Ctx; StringRef Name; StringRef PrintedName; unsigned TheKind : 4; NodeVector Children; std::set Annotations; std::map AnnotateComments; NodePtr Parent = nullptr; protected: SDKNode(SDKNodeInitInfo Info, SDKNodeKind Kind); virtual ~SDKNode() = default; public: static SDKNode *constructSDKNode(SDKContext &Ctx, llvm::yaml::MappingNode *Node); static void preorderVisit(NodePtr Root, SDKNodeVisitor &Visitor); static void postorderVisit(NodePtr Root, SDKNodeVisitor &Visitor); bool operator==(const SDKNode &Other) const; bool operator!=(const SDKNode &Other) const { return !((*this) == Other); } void output(json::Output &out, KeyKind Key, bool Value); void output(json::Output &out, KeyKind Key, StringRef Value); ArrayRef getAnnotations(std::vector &Scratch) const; bool isLeaf() const { return Children.empty(); } SDKNodeKind getKind() const { return SDKNodeKind(TheKind); } StringRef getName() const { return Name; } bool isNameValid() const { return Name != "_"; } StringRef getPrintedName() const { return PrintedName; } void removeChild(ChildIt CI) { Children.erase(CI); } ChildIt getChildBegin() { return Children.begin(); } void annotate(NodeAnnotation Anno) { Annotations.insert(Anno); } void annotate(NodeAnnotation Anno, StringRef Comment); void removeAnnotate(NodeAnnotation Anno); NodePtr getParent() const { return Parent; }; unsigned getChildrenCount() const { return Children.size(); } NodePtr childAt(unsigned I) const; void removeChild(NodePtr C); StringRef getAnnotateComment(NodeAnnotation Anno) const; bool isAnnotatedAs(NodeAnnotation Anno) const; void addChild(SDKNode *Child); NodeVector& getChildren() { return Children; } ArrayRef getChildren() const { return Children; } bool hasSameChildren(const SDKNode &Other) const; unsigned getChildIndex(const SDKNode *Child) const; SDKNode* getOnlyChild() const; SDKContext &getSDKContext() const { return Ctx; } SDKNodeRoot *getRootNode() const; virtual void jsonize(json::Output &Out); virtual void diagnose(SDKNode *Right) {}; template const T *getAs() const { if (T::classof(this)) return static_cast(this); llvm_unreachable("incompatible types"); } template T *getAs() { if (T::classof(this)) return static_cast(this); llvm_unreachable("incompatible types"); } }; class SDKNodeDecl: public SDKNode { DeclKind DKind; StringRef Usr; StringRef Location; StringRef ModuleName; std::vector DeclAttributes; bool IsImplicit; bool IsStatic; bool IsDeprecated; bool IsProtocolReq; bool IsOverriding; bool IsOpen; bool IsInternal; bool IsABIPlaceholder; uint8_t ReferenceOwnership; StringRef GenericSig; Optional FixedBinaryOrder; protected: SDKNodeDecl(SDKNodeInitInfo Info, SDKNodeKind Kind); virtual ~SDKNodeDecl() = default; public: StringRef getUsr() const { return Usr; } StringRef getLocation() const { return Location; } StringRef getModuleName() const {return ModuleName;} StringRef getHeaderName() const; ArrayRef getDeclAttributes() const; bool hasAttributeChange(const SDKNodeDecl &Another) const; swift::ReferenceOwnership getReferenceOwnership() const { return swift::ReferenceOwnership(ReferenceOwnership); } bool isObjc() const { return Usr.startswith("c:"); } static bool classof(const SDKNode *N); DeclKind getDeclKind() const { return DKind; } void printFullyQualifiedName(llvm::raw_ostream &OS) const; StringRef getFullyQualifiedName() const; bool isDeprecated() const { return IsDeprecated; }; bool isProtocolRequirement() const { return IsProtocolReq; } bool isNonOptionalProtocolRequirement() const; bool hasDeclAttribute(DeclAttrKind DAKind) const; bool isImplicit() const { return IsImplicit; }; bool isStatic() const { return IsStatic; }; bool isOverriding() const { return IsOverriding; }; bool isOptional() const { return hasDeclAttribute(DeclAttrKind::DAK_Optional); } bool isOpen() const { return IsOpen; } bool isInternal() const { return IsInternal; } bool isABIPlaceholder() const { return IsABIPlaceholder; } StringRef getGenericSignature() const { return GenericSig; } StringRef getScreenInfo() const; bool hasFixedBinaryOrder() const { return FixedBinaryOrder.hasValue(); } uint8_t getFixedBinaryOrder() const { return *FixedBinaryOrder; } virtual void jsonize(json::Output &Out) override; virtual void diagnose(SDKNode *Right) override; // The first argument of the diag is always screening info. template void emitDiag(Diag ID, typename detail::PassArgument::type... Args) const { // Don't emit objc decls if we care about swift exclusively if (Ctx.getOpts().SwiftOnly) { if (isObjc()) return; } Ctx.getDiags().diagnose(SourceLoc(), ID, getScreenInfo(), std::move(Args)...); } }; class SDKNodeRoot: public SDKNode { /// This keeps track of all decl descendants with USRs. llvm::StringMap> DescendantDeclTable; public: SDKNodeRoot(SDKNodeInitInfo Info); static SDKNode *getInstance(SDKContext &Ctx); static bool classof(const SDKNode *N); void registerDescendant(SDKNode *D); ArrayRef getDescendantsByUsr(StringRef Usr) { return DescendantDeclTable[Usr].getArrayRef(); } }; class SDKNodeType: public SDKNode { std::vector TypeAttributes; bool HasDefaultArg; // Empty() implies "Default" StringRef ParamValueOwnership; protected: SDKNodeType(SDKNodeInitInfo Info, SDKNodeKind Kind); ~SDKNodeType() = default; public: bool hasTypeAttribute(TypeAttrKind DAKind) const; KnownTypeKind getTypeKind() const; void addTypeAttribute(TypeAttrKind AttrKind); ArrayRef getTypeAttributes() const; SDKNodeDecl *getClosestParentDecl() const; // When the type node represents a function parameter, this function returns // whether the parameter has a default value. bool hasDefaultArgument() const { return HasDefaultArg; } bool isTopLevelType() const { return !isa(getParent()); } StringRef getTypeRoleDescription() const; StringRef getParamValueOwnership() const; static bool classof(const SDKNode *N); virtual void jsonize(json::Output &Out) override; virtual void diagnose(SDKNode *Right) override; bool hasAttributeChange(const SDKNodeType &Another) const; }; class SDKNodeTypeNominal : public SDKNodeType { StringRef USR; public: SDKNodeTypeNominal(SDKNodeInitInfo Info); // Get the usr of the correspoding nominal type decl. StringRef getUsr() const { return USR; } static bool classof(const SDKNode *N); void jsonize(json::Output &Out) override; }; class SDKNodeTypeFunc : public SDKNodeType { public: SDKNodeTypeFunc(SDKNodeInitInfo Info); bool isEscaping() const { return hasTypeAttribute(TypeAttrKind::TAK_noescape); } static bool classof(const SDKNode *N); void diagnose(SDKNode *Right) override; }; class SDKNodeTypeAlias : public SDKNodeType { public: SDKNodeTypeAlias(SDKNodeInitInfo Info); const SDKNodeType *getUnderlyingType() const { return getOnlyChild()->getAs(); } static bool classof(const SDKNode *N); }; class SDKNodeVectorViewer { ArrayRef Collection; llvm::function_ref Selector; typedef ArrayRef::iterator VectorIt; VectorIt getNext(VectorIt Start); class ViewerIterator; public: SDKNodeVectorViewer(ArrayRef Collection, llvm::function_ref Selector) : Collection(Collection), Selector(Selector) {} ViewerIterator begin(); ViewerIterator end(); }; class SDKNodeVectorViewer::ViewerIterator : public std::iterator { SDKNodeVectorViewer &Viewer; VectorIt P; public: ViewerIterator(SDKNodeVectorViewer &Viewer, VectorIt P) : Viewer(Viewer), P(P) {} ViewerIterator(const ViewerIterator& mit) : Viewer(mit.Viewer), P(mit.P) {} ViewerIterator& operator++(); ViewerIterator operator++(int) {ViewerIterator tmp(*this); operator++(); return tmp;} bool operator==(const ViewerIterator& rhs) {return P==rhs.P;} bool operator!=(const ViewerIterator& rhs) {return P!=rhs.P;} const NodePtr& operator*() {return *P;} }; class SDKNodeDeclType: public SDKNodeDecl { StringRef SuperclassUsr; std::vector SuperclassNames; 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(); }; #define NOMINAL_TYPE_DECL(ID, PARENT) \ bool is##ID() const { return getDeclKind() == DeclKind::ID; } #define DECL(ID, PARENT) #include "swift/AST/DeclNodes.def" StringRef getEnumRawTypeName() const { assert(isEnum()); return EnumRawTypeName; } Optional getSuperclass() const; /// Finding the node through all children, including the inheritted ones, /// whose printed name matches with the given name. Optional lookupChildByPrintedName(StringRef Name) const; SDKNodeType *getRawValueType() const; bool isConformingTo(KnownProtocolKind Kind) const; void jsonize(json::Output &out) override; 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; bool IsABIPlaceholder; public: SDKNodeConformance(SDKNodeInitInfo Info); ArrayRef getTypeWitnesses() const { return Children; } SDKNodeDeclType *getNominalTypeDecl() const { return TypeDecl; } bool isABIPlaceholder() const { return IsABIPlaceholder; } void jsonize(json::Output &out) override; 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); StringRef getWitnessedTypeName() const; SDKNodeType *getUnderlyingType() const; static bool classof(const SDKNode *N); }; class SDKNodeDeclOperator : public SDKNodeDecl { public: SDKNodeDeclOperator(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); void diagnose(SDKNode *Right) override; }; class SDKNodeDeclTypeAlias : public SDKNodeDecl { public: SDKNodeDeclTypeAlias(SDKNodeInitInfo Info); const SDKNodeType* getUnderlyingType() const { return getOnlyChild()->getAs(); } static bool classof(const SDKNode *N); }; class SDKNodeDeclAssociatedType: public SDKNodeDecl { public: SDKNodeDeclAssociatedType(SDKNodeInitInfo Info); const SDKNodeType* getDefault() const { return getChildrenCount() ? getOnlyChild()->getAs(): nullptr; } static bool classof(const SDKNode *N); }; class SDKNodeDeclVar : public SDKNodeDecl { bool IsLet; bool HasStorage; bool HasDidSet; bool HasWillSet; public: SDKNodeDeclVar(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); SDKNodeDeclGetter *getGetter() const; SDKNodeDeclSetter *getSetter() const; SDKNodeType *getType() const; bool isLet() const { return IsLet; } void jsonize(json::Output &Out) override; void diagnose(SDKNode *Right) override; bool hasStorage() const { return HasStorage; } bool hasDidSet() const { return HasDidSet; } bool hasWillSet() const { return HasWillSet; } }; class SDKNodeDeclAbstractFunc : public SDKNodeDecl { bool IsThrowing; bool ReqNewWitnessTableEntry; Optional SelfIndex; protected: SDKNodeDeclAbstractFunc(SDKNodeInitInfo Info, SDKNodeKind Kind); virtual ~SDKNodeDeclAbstractFunc() = default; public: bool isThrowing() const { return IsThrowing; } bool reqNewWitnessTableEntry() const { return ReqNewWitnessTableEntry; } uint8_t getSelfIndex() const { return SelfIndex.getValue(); } Optional getSelfIndexOptional() const { return SelfIndex; } bool hasSelfIndex() const { return SelfIndex.hasValue(); } static bool classof(const SDKNode *N); virtual void jsonize(json::Output &out) override; static StringRef getTypeRoleDescription(SDKContext &Ctx, unsigned Index); virtual void diagnose(SDKNode *Right) override; }; class SDKNodeDeclSubscript: public SDKNodeDeclAbstractFunc { bool HasSetter; bool HasStorage; bool HasDidSet; bool HasWillSet; public: SDKNodeDeclSubscript(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); bool hasSetter() const { return HasSetter; } bool hasStorage() const { return HasStorage; } void jsonize(json::Output &Out) override; void diagnose(SDKNode *Right) override; bool hasDidSet() const { return HasDidSet; } bool hasWillSet() const { return HasWillSet; } }; class SDKNodeDeclFunction: public SDKNodeDeclAbstractFunc { StringRef FuncSelfKind; public: SDKNodeDeclFunction(SDKNodeInitInfo Info); SDKNode *getReturnType() { return *getChildBegin(); } StringRef getSelfAccessKind() const { return FuncSelfKind; } static bool classof(const SDKNode *N); void jsonize(json::Output &Out) override; void diagnose(SDKNode *Right) override; }; class SDKNodeDeclConstructor: public SDKNodeDeclAbstractFunc { public: SDKNodeDeclConstructor(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); }; class SDKNodeDeclGetter: public SDKNodeDeclAbstractFunc { public: SDKNodeDeclGetter(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); }; class SDKNodeDeclSetter: public SDKNodeDeclAbstractFunc { public: SDKNodeDeclSetter(SDKNodeInitInfo Info); static bool classof(const SDKNode *N); }; // The additional information we need for a type node in the digest. // We use type node to represent entities more than types, e.g. parameters, so // this struct is necessary to pass down to create a type node. struct TypeInitInfo { bool IsImplicitlyUnwrappedOptional = false; bool hasDefaultArgument = false; StringRef ValueOwnership; }; class SwiftDeclCollector: public VisibleDeclConsumer { SDKContext &Ctx; std::vector> OwnedBuffers; SDKNode *RootNode; llvm::SetVector KnownDecls; // Collected and sorted after we get all of them. std::vector ClangMacros; std::set HandledExtensions; public: void visitAllRoots(SDKNodeVisitor &Visitor) { SDKNode::preorderVisit(RootNode, Visitor); } SwiftDeclCollector(SDKContext &Ctx) : Ctx(Ctx), RootNode(SDKNodeRoot::getInstance(Ctx)) {} // Construct all roots vector from a given file where a forest was // previously dumped. void deSerialize(StringRef Filename); // Serialize the content of all roots to a given file using JSON format. void serialize(StringRef Filename); // After collecting decls, either from imported modules or from a previously // serialized JSON file, using this function to get the root of the SDK. SDKNodeRoot* getSDKRoot() { return static_cast(RootNode); } void printTopLevelNames(); /// Adds all conformances from the provided NominalTypeDecl to the provided /// SDK node for that type decl. 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); SDKNode *constructVarNode(ValueDecl *VD); SDKNode *constructExternalExtensionNode(NominalTypeDecl *NTD, ArrayRef AllExts); SDKNode *constructTypeDeclNode(NominalTypeDecl *NTD); SDKNode *constructInitNode(ConstructorDecl *CD); SDKNode *constructFunctionNode(FuncDecl* FD, SDKNodeKind Kind); SDKNode *constructOperatorDeclNode(OperatorDecl *OD); std::vector createParameterNodes(ParameterList *PL); SDKNode *constructTypeNode(Type T, TypeInitInfo Info = TypeInitInfo()); void processValueDecl(ValueDecl *VD); void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason, DynamicLookupInfo dynamicLookupInfo = {}) override; void processDecl(Decl *D); public: void lookupVisibleDecls(ArrayRef Modules); }; int dumpSwiftModules(const CompilerInvocation &InitInvok, const llvm::StringSet<> &ModuleNames, StringRef OutputDir, const std::vector PrintApis, CheckerOptions Opts); int dumpSDKContent(const CompilerInvocation &InitInvok, const llvm::StringSet<> &ModuleNames, StringRef OutputFile, CheckerOptions Opts); /// Mostly for testing purposes, this function de-serializes the SDK dump in /// dumpPath and re-serialize them to OutputPath. If the tool performs correctly, /// the contents in dumpPath and OutputPath should be identical. int deserializeSDKDump(StringRef dumpPath, StringRef OutputPath, CheckerOptions Opts); int findDeclUsr(StringRef dumpPath, CheckerOptions Opts); void nodeSetDifference(ArrayRef Left, ArrayRef Right, NodeVector &LeftMinusRight, NodeVector &RightMinusLeft); } // end of abi namespace } // end of ide namespace } // end of Swift namespace #endif