text: //===--- 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 <functional>
  
  namespace swift {
  namespace json {
  class Output;
  }
  namespace ide {
  namespace api {
  
  class SDKNode;
  typedef SDKNode* NodePtr;
  typedef std::map<NodePtr, NodePtr> ParentMap;
  typedef std::map<NodePtr, NodePtr> NodeMap;
  typedef std::vector<NodePtr> NodeVector;
  typedef std::vector<CommonDiffItem> DiffVector;
  typedef std::vector<TypeMemberDiffItem> TypeMemberDiffVector;
  typedef llvm::MapVector<NodePtr, NodePtr> 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<BreakingAttributeInfo> BreakingAttrs;
    /// This is to cache the equal comparison results between nodes.
    llvm::DenseMap<const SDKNode*, llvm::DenseMap<const SDKNode*, bool>> 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<BreakingAttributeInfo> getBreakingAttributeInfo() const { return BreakingAttrs; }
    Optional<uint8_t> getFixedBinaryOrder(ValueDecl *VD) const;
  
    template<class YAMLNodeTy, typename ...ArgTypes>
    void diagnose(YAMLNodeTy node, Diag<ArgTypes...> ID,
                  typename detail::PassArgument<ArgTypes>::type... args) {
      auto smRange = node->getSourceRange();
      auto range = SourceRange(SourceLoc(smRange.Start), SourceLoc(smRange.End));
      Diags.diagnose(range.Start, ID, std::forward<ArgTypes>(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<SDKNode*>::iterator ChildIt;
  protected:
    SDKContext &Ctx;
    StringRef Name;
    StringRef PrintedName;
    unsigned TheKind : 4;
    NodeVector Children;
    std::set<NodeAnnotation> Annotations;
    std::map<NodeAnnotation, StringRef> 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<NodeAnnotation>
      getAnnotations(std::vector<NodeAnnotation> &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<SDKNode*> 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 <typename T> const T *getAs() const {
      if (T::classof(this))
        return static_cast<const T*>(this);
      llvm_unreachable("incompatible types");
    }
    template <typename T> T *getAs() {
      if (T::classof(this))
        return static_cast<T*>(this);
      llvm_unreachable("incompatible types");
    }
  };
  
  class SDKNodeDecl: public SDKNode {
    DeclKind DKind;
    StringRef Usr;
    StringRef Location;
    StringRef ModuleName;
    std::vector<DeclAttrKind> DeclAttributes;
    bool IsImplicit;
    bool IsStatic;
    bool IsDeprecated;
    bool IsProtocolReq;
    bool IsOverriding;
    bool IsOpen;
    bool IsInternal;
    bool IsABIPlaceholder;
    uint8_t ReferenceOwnership;
    StringRef GenericSig;
    Optional<uint8_t> 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<DeclAttrKind> 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<typename ...ArgTypes>
    void emitDiag(Diag<StringRef, ArgTypes...> ID,
                  typename detail::PassArgument<ArgTypes>::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<llvm::SmallSetVector<SDKNodeDecl*, 2>> DescendantDeclTable;
  
  public:
    SDKNodeRoot(SDKNodeInitInfo Info);
    static SDKNode *getInstance(SDKContext &Ctx);
    static bool classof(const SDKNode *N);
    void registerDescendant(SDKNode *D);
    ArrayRef<SDKNodeDecl*> getDescendantsByUsr(StringRef Usr) {
      return DescendantDeclTable[Usr].getArrayRef();
    }
  };
  
  class SDKNodeType: public SDKNode {
    std::vector<TypeAttrKind> 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<TypeAttrKind> 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<SDKNodeType>(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<SDKNodeType>();
    }
    static bool classof(const SDKNode *N);
  };
  
  class SDKNodeVectorViewer {
    ArrayRef<SDKNode*> Collection;
    llvm::function_ref<bool(NodePtr)> Selector;
    typedef ArrayRef<SDKNode*>::iterator VectorIt;
    VectorIt getNext(VectorIt Start);
    class ViewerIterator;
  
  public:
    SDKNodeVectorViewer(ArrayRef<SDKNode*> Collection,
                        llvm::function_ref<bool(NodePtr)> Selector) :
                          Collection(Collection),
                          Selector(Selector) {}
    ViewerIterator begin();
    ViewerIterator end();
  };
  
  class SDKNodeVectorViewer::ViewerIterator :
      public std::iterator<std::input_iterator_tag, VectorIt> {
    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<StringRef> SuperclassNames;
    std::vector<SDKNode*> Conformances;
    StringRef EnumRawTypeName;
  public:
    SDKNodeDeclType(SDKNodeInitInfo Info);
    static bool classof(const SDKNode *N);
    StringRef getSuperClassUsr() const { return SuperclassUsr; }
    ArrayRef<StringRef> getClassInheritanceChain() const { return SuperclassNames; }
    void addConformance(SDKNode *Conf);
    ArrayRef<SDKNode*> 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<SDKNodeDeclType*> getSuperclass() const;
  
    /// Finding the node through all children, including the inheritted ones,
    /// whose printed name matches with the given name.
    Optional<SDKNodeDecl*> 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<SDKNode*> 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<SDKNodeType>();
    }
    static bool classof(const SDKNode *N);
  };
  
  class SDKNodeDeclAssociatedType: public SDKNodeDecl {
  public:
    SDKNodeDeclAssociatedType(SDKNodeInitInfo Info);
    const SDKNodeType* getDefault() const {
      return getChildrenCount() ? getOnlyChild()->getAs<SDKNodeType>(): 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<uint8_t> 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<uint8_t> 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<std::unique_ptr<llvm::MemoryBuffer>> OwnedBuffers;
    SDKNode *RootNode;
    llvm::SetVector<Decl*> KnownDecls;
    // Collected and sorted after we get all of them.
    std::vector<ValueDecl *> ClangMacros;
    std::set<ExtensionDecl*> 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<SDKNodeRoot*>(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<ExtensionDecl*> AllExts);
    SDKNode *constructTypeDeclNode(NominalTypeDecl *NTD);
    SDKNode *constructInitNode(ConstructorDecl *CD);
    SDKNode *constructFunctionNode(FuncDecl* FD, SDKNodeKind Kind);
    SDKNode *constructOperatorDeclNode(OperatorDecl *OD);
    std::vector<SDKNode*> createParameterNodes(ParameterList *PL);
    SDKNode *constructTypeNode(Type T, TypeInitInfo Info = TypeInitInfo());
    void processValueDecl(ValueDecl *VD);
    void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override;
    void processDecl(Decl *D);
  public:
    void lookupVisibleDecls(ArrayRef<ModuleDecl *> Modules);
  };
  
  int dumpSwiftModules(const CompilerInvocation &InitInvok,
                       const llvm::StringSet<> &ModuleNames,
                       StringRef OutputDir,
                       const std::vector<std::string> 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<SDKNode*> Left, ArrayRef<SDKNode*> Right,
    NodeVector &LeftMinusRight, NodeVector &RightMinusLeft);
  
  } // end of abi namespace
  } // end of ide namespace
  } // end of Swift namespace
  
  #endif
  