blob: eb5c0a112c5b7a5f3160ff0a5ec0ad15c77c9e2d [file] [log] [blame]
/*
* Copyright (C) 2015 Square, Inc.
*
* 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
*
* http://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.
*/
@file:JvmName("WildcardTypeNames")
package com.squareup.kotlinpoet
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
import javax.lang.model.element.TypeParameterElement
import kotlin.reflect.KClass
class WildcardTypeName private constructor(
upperBounds: List<TypeName>,
lowerBounds: List<TypeName>,
nullable: Boolean = false,
annotations: List<AnnotationSpec> = emptyList()
) : TypeName(nullable, annotations) {
val upperBounds = upperBounds.toImmutableList()
val lowerBounds = lowerBounds.toImmutableList()
init {
require(this.upperBounds.size == 1) { "unexpected extends bounds: $upperBounds" }
}
override fun asNullable() = WildcardTypeName(upperBounds, lowerBounds, true, annotations)
override fun asNonNullable() = WildcardTypeName(upperBounds, lowerBounds, false, annotations)
override fun annotated(annotations: List<AnnotationSpec>): WildcardTypeName {
return WildcardTypeName(upperBounds, lowerBounds, nullable, this.annotations + annotations)
}
override fun withoutAnnotations() = WildcardTypeName(upperBounds, lowerBounds, nullable)
override fun emit(out: CodeWriter): CodeWriter {
if (lowerBounds.size == 1) {
return out.emitCode("in %T", lowerBounds[0])
}
return if (upperBounds[0] == ANY)
out.emit("*") else
out.emitCode("out %T", upperBounds[0])
}
companion object {
/**
* Returns a type that represents an unknown type that extends `bound`. For example, if `bound`
* is `CharSequence.class`, this returns `? extends CharSequence`. If `bound` is `Object.class`,
* this returns `?`, which is shorthand for `? extends Object`.
*/
@JvmStatic fun subtypeOf(upperBound: TypeName): WildcardTypeName {
return WildcardTypeName(listOf(upperBound), emptyList())
}
@JvmStatic fun subtypeOf(upperBound: Type) = subtypeOf(upperBound.asTypeName())
@JvmStatic fun subtypeOf(upperBound: KClass<*>) = subtypeOf(upperBound.asTypeName())
/**
* Returns a type that represents an unknown supertype of `bound`. For example, if `bound` is
* `String.class`, this returns `? super String`.
*/
@JvmStatic fun supertypeOf(lowerBound: TypeName): WildcardTypeName {
return WildcardTypeName(listOf(ANY), listOf(lowerBound))
}
@JvmStatic fun supertypeOf(lowerBound: Type) = supertypeOf(lowerBound.asTypeName())
@JvmStatic fun supertypeOf(lowerBound: KClass<*>) = supertypeOf(lowerBound.asTypeName())
internal fun get(
mirror: javax.lang.model.type.WildcardType,
typeVariables: MutableMap<TypeParameterElement, TypeVariableName>)
: TypeName {
val extendsBound = mirror.extendsBound
if (extendsBound == null) {
val superBound = mirror.superBound
return if (superBound == null)
subtypeOf(ANY) else
supertypeOf(TypeName.get(superBound, typeVariables))
} else {
return subtypeOf(TypeName.get(extendsBound, typeVariables))
}
}
internal fun get(
wildcardName: WildcardType,
map: MutableMap<Type, TypeVariableName>)
: TypeName {
return WildcardTypeName(
wildcardName.upperBounds.map { TypeName.get(it, map = map) },
wildcardName.lowerBounds.map { TypeName.get(it, map = map) })
}
}
}
@JvmName("get")
fun javax.lang.model.type.WildcardType.asWildcardTypeName()
= WildcardTypeName.get(this, mutableMapOf())
@JvmName("get")
fun WildcardType.asWildcardTypeName() = WildcardTypeName.get(this, mutableMapOf())