Steepコードリーディング(6日目)

# Steepコードリーディング(6日目)

今回は以下のJobが何をしているのかざっくりと追い、目的の型検査のJobを見つける。

- `StartTypeCheckJob`
- `ValidateAppSignatureJob`
- `ValidateLibrarySignatureJob`
- `TypeCheckCodeJob`
- `WorkspaceSymbolJob`
- `StatsJob`
- `GotoJob`

と意気込んでいたが、Job自体は単なるStructオブジェクトに過ぎなかった。

```rb
WorkspaceSymbolJob = _ = Struct.new(:query, :id, keyword_init: true)
StatsJob = _ = Struct.new(:id, keyword_init: true)
StartTypeCheckJob = _ = Struct.new(:guid, :changes, keyword_init: true)
TypeCheckCodeJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
ValidateAppSignatureJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
ValidateLibrarySignatureJob = _ = Struct.new(:guid, :path, :target, keyword_init: true)
class GotoJob < Struct.new(:id, :kind, :params, keyword_init: true)
  def self.implementation(id:, params:)
    new(
      kind: :implementation,
      id: id,
      params: params
    )
  end

  def self.definition(id:, params:)
    new(
      kind: :definition,
      id: id,
      params: params
    )
  end

  def self.type_definition(id:, params:)
    new(
      kind: :type_definition,
      id: id,
      params: params
    )
  end

  def implementation?
    kind == :implementation
  end

  def definition?
    kind == :definition
  end

  def type_definition?
    kind == :type_definition
  end
end
```

仕方ないので`handle_job`での処理内容からいくつかあたりをつけて追っていくことにする。

### `StartTypeCheckJob`

ログを吐いて`service.update`を行っている。

```rb
when StartTypeCheckJob
  Steep.logger.info { "Processing StartTypeCheckJob for guid=#{job.guid}" }
  service.update(changes: job.changes)
```

`service`メソッドの中身はこれ。

```rb
def service
  @service ||= Services::TypeCheckService.new(project: project)
end
```

ん？なんか早くもゴールを見つけた気がする...？

### `ValidateAppSignatureJob`

`service.validate_signature`を行っている。メソッド名から察するにRBSのSyntaxチェックとかだろうか。

```rb
when ValidateAppSignatureJob
  if job.guid == current_type_check_guid
    Steep.logger.info { "Processing ValidateAppSignature for guid=#{job.guid}, path=#{job.path}" }

    formatter = Diagnostic::LSPFormatter.new({}, **{})

    diagnostics = service.validate_signature(path: project.relative_path(job.path), target: job.target)

    typecheck_progress(
      path: job.path,
      guid: job.guid,
      target: job.target,
      diagnostics: diagnostics.filter_map { formatter.format(_1) }
    )
  end
```

`typecheck_progress`はこれ。

```rb
def typecheck_progress(guid:, path:, target:, diagnostics:)
  writer.write(CustomMethods::TypeCheck__Progress.notification({ guid: guid, path: path.to_s, target: target.name.to_s, diagnostics: diagnostics }))
end
```

### `ValidateLibrarySignatureJob`

これも`service.validate_signature`を行っている。差分でいうとpathがprojectではなくjobの持っているpathになっていること。名前から察するにgem_rbs_collectionやRBS本体が持っているライブラリのRBSのSyntaxチェックとかだろうか。

```rb
when ValidateLibrarySignatureJob
  if job.guid == current_type_check_guid
    Steep.logger.info { "Processing ValidateLibrarySignature for guid=#{job.guid}, path=#{job.path}" }

    formatter = Diagnostic::LSPFormatter.new({}, **{})
    diagnostics = service.validate_signature(path: job.path, target: job.target)

    typecheck_progress(path: job.path, guid: job.guid, target: job.target, diagnostics: diagnostics.filter_map { formatter.format(_1) })
  end
```

### `TypeCheckCodeJob`

`service.typecheck_source`を実行している。直前で出てくる変数名や`typecheck_source`というメソッド名がいかにもアプリケーションの型検査していますと言っている。

```rb
when TypeCheckCodeJob
  if job.guid == current_type_check_guid
    Steep.logger.info { "Processing TypeCheckCodeJob for guid=#{job.guid}, path=#{job.path}, target=#{job.target.name}" }
    group_target = project.group_for_source_path(job.path) || job.target
    formatter = Diagnostic::LSPFormatter.new(group_target.code_diagnostics_config)
    relative_path = project.relative_path(job.path)
    diagnostics = service.typecheck_source(path: relative_path, target: job.target)
    typecheck_progress(path: job.path, guid: job.guid, target: job.target, diagnostics: diagnostics&.filter_map { formatter.format(_1) })
  end
```

ここまでで、型検査自体は`service.typecheck_source`、Syntaxチェックなどは`service.validate_signature`を追っていけば良さそうなあたりがついた。

### `WorkspaceSymbolJob`、`StatsJob`、`GotoJob`

標準入力に何か入力していそうだけど、型検査自体とは無関係と見て良さそう。

```rb
when WorkspaceSymbolJob
  writer.write(
    id: job.id,
    result: workspace_symbol_result(job.query)
  )
when StatsJob
  writer.write(
    id: job.id,
    result: stats_result().map(&:as_json)
  )
when GotoJob
  writer.write(
    id: job.id,
    result: goto(job)
  )
end
```

以後型検査周りは`service.typecheck_source`と`service.validate_signature`を追っていけば良さそうなあたりがついた。今興味があるのは型検査部分なので、ひとまず`service.typecheck_source`を追い、時間が余れば`service.validate_signature`も見ていく感じとしていきたい。