All Downloads are FREE. Search and download functionalities are using the official Maven repository.

main.dev.zacsweers.moshix.ir.compiler.api.PropertyGenerator.kt Maven / Gradle / Ivy

There is a newer version: 1.7.20-Beta-0.18.3
Show newest version
/*
 * Copyright (C) 2018 Zac Sweers
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dev.zacsweers.moshix.ir.compiler.api

import dev.zacsweers.moshix.ir.compiler.util.NameAllocator
import dev.zacsweers.moshix.ir.compiler.util.defaultPrimitiveValue
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.ir.builders.IrStatementsBuilder
import org.jetbrains.kotlin.ir.builders.irBoolean
import org.jetbrains.kotlin.ir.builders.irNull
import org.jetbrains.kotlin.ir.builders.irTemporary
import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.types.makeNullable

/** Generates functions to encode and decode a property as JSON. */
internal class PropertyGenerator(
  val target: TargetProperty,
  val delegateKey: DelegateKey,
  val isTransientOrIgnored: Boolean = false
) {
  val name: String = target.name
  val jsonName: String = target.jsonName ?: target.name
  val hasDefault: Boolean = target.hasDefault

  lateinit var localName: String
  lateinit var localIsPresentName: String
  lateinit var localHasErrorName: String

  val isRequired: Boolean
    get() = !delegateKey.nullable && !hasDefault

  val hasConstructorParameter: Boolean
    get() = target.parameterIndex != -1

  /**
   * IsPresent is required if the following conditions are met:
   * - Is not transient
   * - Has a default
   * - Is not a constructor parameter (for constructors we use a defaults mask)
   * - Is nullable (because we differentiate absent from null)
   *
   * This is used to indicate that presence should be checked first before possible assigning null
   * to an absent value
   */
  val hasLocalIsPresentName: Boolean =
    !isTransientOrIgnored && hasDefault && !hasConstructorParameter && delegateKey.nullable
  val hasConstructorDefault: Boolean = hasDefault && hasConstructorParameter

  internal fun allocateNames(nameAllocator: NameAllocator) {
    localName = nameAllocator.newName(name)
    localIsPresentName = nameAllocator.newName("${name}Set")
    localHasErrorName = nameAllocator.newName("${name}HasError")
  }

  internal fun generateLocalProperty(
    builder: IrStatementsBuilder<*>,
    pluginContext: IrPluginContext
  ): IrVariable {
    builder.apply {
      val expression =
        if (hasConstructorDefault) {
          // We default to the primitive default type, as reflectively invoking the constructor
          // without this (even though it's a throwaway) will fail argument type resolution in
          // the reflective invocation.
          defaultPrimitiveValue(target.type, pluginContext)
        } else {
          irNull(target.type.makeNullable())
        }
      return irTemporary(
        expression,
        isMutable = true,
        nameHint = localName,
        irType = expression.type
      )
    }
  }

  internal fun generateLocalIsPresentProperty(
    builder: IrStatementsBuilder<*>,
    pluginContext: IrPluginContext
  ): IrVariable {
    builder.apply {
      return irTemporary(
        irBoolean(false),
        isMutable = true,
        nameHint = localIsPresentName,
        irType = pluginContext.irBuiltIns.booleanType
      )
    }
  }

  internal fun generateLocalHasErrorProperty(
    builder: IrStatementsBuilder<*>,
    pluginContext: IrPluginContext
  ): IrVariable {
    builder.apply {
      return irTemporary(
        irBoolean(false),
        isMutable = true,
        nameHint = localHasErrorName,
        irType = pluginContext.irBuiltIns.booleanType
      )
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy