<commit_before>//
//  DIContainer+getGraph.swift
//  DITranquillity
//
//  Created by <NAME>. on 30.06.2020.
//  Copyright © 2020 <NAME>. All rights reserved.
//

extension DIContainer {

  /// Make graph for public usage.
  /// Your can call `checkIsValid` for check for correct.
  /// Or Your can use this graph for dependency analysis.
  /// - Returns: Dependency graph
  public func makeGraph() -> DIGraph {
    let components = componentContainer.components

    var edgeId: Int = 0
    var vertices: [DIVertex] = components.map { .component(DIComponentVertex(component: $0)) }
    var adjacencyList: DIGraph.AdjacencyList = Array(repeating: [], count: vertices.count)

    for (index, component) in components.enumerated() {
      // get all paramaters - from init and injection
      let parametersInfo = componentParametersInfo(component: component)
      for (parameter, initial, cycle) in parametersInfo {
        // ignore reference on self
        if parameter.parsedType.useObject {
          continue
        }

        edgeId += 1
        let edge = DIEdge(by: parameter, id: edgeId, initial: initial, cycle: cycle)

        if addArgumentIfNeeded(by: parameter.parsedType, adjacencyList: &adjacencyList, vertices: &vertices) {
          adjacencyList[index].append((edge, [vertices.count - 1]))
          continue
        }

        let candidates = resolver.findComponents(by: parameter.parsedType, with: parameter.name, from: component.framework)
        let toIndices = candidates.compactMap { findIndex(for: $0, in: components) }

        assert(candidates.count == toIndices.count)
        // not found candidates - need add reference on unknown type
        if toIndices.isEmpty {
          addUnknown(by: parameter.parsedType, adjacencyList: &adjacencyList, vertices: &vertices)
          adjacencyList[index].append((edge, [vertices.count - 1]))
          continue
        }

        adjacencyList[index].append((edge, toIndices))
      }
    }

    return DIGraph(vertices: vertices, adjacencyList: adjacencyList)
  }

  private func findIndex(for component: Component, in components: [Component]) -> Int? {
    if components.isEmpty {
      return nil
    }

    let count = components.count
    var left = 0
    var right = count

    while left <= right {
      let center = (right + left) / 2
      if components[center] === component {
        return center
      }

      if component.order < components[center].order {
        right = center - 1
      } else {
        left = center + 1
      }
    }

    return nil
  }

  private func addArgumentIfNeeded(by parsedType: ParsedType, adjacencyList: inout DIGraph.AdjacencyList, vertices: inout [DIVertex]) -> Bool {
    if !parsedType.arg {
      return false
    }

    guard let argType = parsedType.sType?.type else {
      return false
    }

    let id = vertices.count
    addVertex(DIVertex.argument(DIArgumentVertex(id: id, type: argType)), adjacencyList: &adjacencyList, vertices: &vertices)
    return true
  }

  private func addUnknown(by parsedType: ParsedType, adjacencyList: inout DIGraph.AdjacencyList, vertices: inout [DIVertex]) {
    let id = vertices.count
    addVertex(DIVertex.unknown(DIUnknownVertex(id: id, type: parsedType.type)), adjacencyList: &adjacencyList, vertices: &vertices)
  }

  private func addVertex(_ vertex: DIVertex, adjacencyList: inout DIGraph.AdjacencyList, vertices: inout [DIVertex]) {
    adjacencyList.append([])
    vertices.append(vertex)
  }

  typealias ParameterInfo = (parameter: MethodSignature.Parameter, initial: Bool, cycle: Bool)
  private func componentParametersInfo(component: Component) -> [ParameterInfo] {
    var result: [ParameterInfo] = []

    if let initial = component.initial {
      result.append(contentsOf: initial.parameters.map { ($0, true, false) })
    }
<commit_msg>fix unknown and arg type<commit_after>//
//  DIContainer+getGraph.swift
//  DITranquillity
//
//  Created by <NAME>. on 30.06.2020.
//  Copyright © 2020 <NAME>. All rights reserved.
//

extension DIContainer {

  /// Make graph for public usage.
  /// Your can call `checkIsValid` for check for correct.
  /// Or Your can use this graph for dependency analysis.
  /// - Returns: Dependency graph
  public func makeGraph() -> DIGraph {
    let components = componentContainer.components

    var edgeId: Int = 0
    var vertices: [DIVertex] = components.map { .component(DIComponentVertex(component: $0)) }
    var adjacencyList: DIGraph.AdjacencyList = Array(repeating: [], count: vertices.count)

    for (index, component) in components.enumerated() {
      // get all paramaters - from init and injection
      let parametersInfo = componentParametersInfo(component: component)
      for (parameter, initial, cycle) in parametersInfo {
        // ignore reference on self
        if parameter.parsedType.useObject {
          continue
        }

        edgeId += 1
        let edge = DIEdge(by: parameter, id: edgeId, initial: initial, cycle: cycle)

        if addArgumentIfNeeded(by: parameter.parsedType, adjacencyList: &adjacencyList, vertices: &vertices) {
          adjacencyList[index].append((edge, [vertices.count - 1]))
          continue
        }

        let candidates = resolver.findComponents(by: parameter.parsedType, with: parameter.name, from: component.framework)
        let toIndices = candidates.compactMap { findIndex(for: $0, in: components) }

        assert(candidates.count == toIndices.count)
        // not found candidates - need add reference on unknown type
        if toIndices.isEmpty {
          addUnknown(by: parameter.parsedType, adjacencyList: &adjacencyList, vertices: &vertices)
          adjacencyList[index].append((edge, [vertices.count - 1]))
          continue
        }

        adjacencyList[index].append((edge, toIndices))
      }
    }

    return DIGraph(vertices: vertices, adjacencyList: adjacencyList)
  }

  private func findIndex(for component: Component, in components: [Component]) -> Int? {
    if components.isEmpty {
      return nil
    }

    let count = components.count
    var left = 0
    var right = count

    while left <= right {
      let center = (right + left) / 2
      if components[center] === component {
        return center
      }

      if component.order < components[center].order {
        right = center - 1
      } else {
        left = center + 1
      }
    }

    return nil
  }

  private func addArgumentIfNeeded(by parsedType: ParsedType, adjacencyList: inout DIGraph.AdjacencyList, vertices: inout [DIVertex]) -> Bool {
    if !parsedType.arg {
      return false
    }

    guard let argType = parsedType.base.sType?.type else {
      return false
    }

    let id = vertices.count
    addVertex(DIVertex.argument(DIArgumentVertex(id: id, type: argType)), adjacencyList: &adjacencyList, vertices: &vertices)
    return true
  }

  private func addUnknown(by parsedType: ParsedType, adjacencyList: inout DIGraph.AdjacencyList, vertices: inout [DIVertex]) {
    let id = vertices.count
    let unknownType = parsedType.base.sType?.type ?? parsedType.base.type

    addVertex(DIVertex.unknown(DIUnknownVertex(id: id, type: unknownType)), adjacencyList: &adjacencyList, vertices: &vertices)
  }

  private func addVertex(_ vertex: DIVertex, adjacencyList: inout DIGraph.AdjacencyList, vertices: inout [DIVertex]) {
    adjacencyList.append([])
    vertices.append(vertex)
  }

  typealias ParameterInfo = (parameter: MethodSignature.Parameter, initial: Bool, cycle: Bool)
  private func componentParametersInfo(component: Component) -> [ParameterInfo] {
    var result: [ParameterInfo] = []

    if let initial = component.initial {
      result.append(contentsOf: initial.parameters.map { ($0, true, false) })
    }

{'fraction_non_alphanumeric': 0.1039380245319561, 'fraction_numerical': 0.005939315687540349, 'mean_word_length': 3.015552099533437, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4544832', 'n_tokens_mistral': 2288, 'n_tokens_neox': 2196, 'n_words': 618}