Skip to content

Commit

Permalink
Merge pull request #676 from square/ralf/rename
Browse files Browse the repository at this point in the history
Rename `FunctionReference` and `PropertyReference`
  • Loading branch information
vRallev authored Jan 12, 2023
2 parents ceb0e12 + 1ffbd4a commit f96e305
Show file tree
Hide file tree
Showing 24 changed files with 528 additions and 526 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
### Custom Code Generator

- Add ability to query top-level functions and properties. The entry point is `projectFiles.topLevelFunctionReferences(module)` and `projectFiles.topLevelPropertyReferences(module)`. This allows you write code generators reacting to top-level functions and properties and not only classes, see #644.
- The `FunctionReference` type has been renamed to `MemberFunctionReference` and a new super type `FunctionReference` has been introduced for `TopLevelFunctionReference` and `MemberFunctionReference`.
- The `PropertyReference` type has been renamed to `MemberPropertyReference` and a new super type `PropertyReference` has been introduced for `TopLevelPropertyReference` and `MemberPropertyReference`.

## [2.4.3] - 2022-12-16

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.jetbrains.kotlin.name.FqName

/**
* This marks any code reference that can be annotated, such as a [ClassReference] or
* [FunctionReference].
* [MemberFunctionReference].
*/
@ExperimentalAnvilApi
public interface AnnotatedReference {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,9 @@ public sealed class AnnotationArgumentReference {
?.singleOrNull { it.name == constantName }
?.let { property ->
return when (property) {
is PropertyReference.Descriptor ->
is MemberPropertyReference.Descriptor ->
property.property.compileTimeInitializer?.value
is PropertyReference.Psi ->
is MemberPropertyReference.Psi ->
// A PropertyReference.property may also be a KtParameter if it's in a constructor,
// but if we're here we're in an object, so the property must be a KtProperty.
(property.property as KtProperty).initializer?.let { parsePrimitiveType(it.text) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ public sealed class ClassReference : Comparable<ClassReference>, AnnotatedRefere
public val shortName: String get() = fqName.shortName().asString()
public val packageFqName: FqName get() = classId.packageFqName

public abstract val constructors: List<FunctionReference>
public abstract val functions: List<FunctionReference>
public abstract val properties: List<PropertyReference>
public abstract val constructors: List<MemberFunctionReference>
public abstract val functions: List<MemberFunctionReference>
public abstract val properties: List<MemberPropertyReference>
public abstract val typeParameters: List<TypeParameterReference>

protected abstract val innerClassesAndObjects: List<ClassReference>
Expand Down Expand Up @@ -131,11 +131,11 @@ public sealed class ClassReference : Comparable<ClassReference>, AnnotatedRefere
) : ClassReference() {
override val fqName: FqName = classId.asSingleFqName()

override val constructors: List<FunctionReference.Psi> by lazy(NONE) {
override val constructors: List<MemberFunctionReference.Psi> by lazy(NONE) {
clazz.allConstructors.map { it.toFunctionReference(this) }
}

override val functions: List<FunctionReference.Psi> by lazy(NONE) {
override val functions: List<MemberFunctionReference.Psi> by lazy(NONE) {
clazz
.children
.filterIsInstance<KtClassBody>()
Expand All @@ -147,7 +147,7 @@ public sealed class ClassReference : Comparable<ClassReference>, AnnotatedRefere
clazz.annotationEntries.map { it.toAnnotationReference(this, module) }
}

override val properties: List<PropertyReference.Psi> by lazy(NONE) {
override val properties: List<MemberPropertyReference.Psi> by lazy(NONE) {
buildList {
// Order kind of matters here, since the Descriptor APIs will list body/member properties
// before the constructor properties.
Expand Down Expand Up @@ -239,11 +239,11 @@ public sealed class ClassReference : Comparable<ClassReference>, AnnotatedRefere
) : ClassReference() {
override val fqName: FqName = classId.asSingleFqName()

override val constructors: List<FunctionReference.Descriptor> by lazy(NONE) {
override val constructors: List<MemberFunctionReference.Descriptor> by lazy(NONE) {
clazz.constructors.map { it.toFunctionReference(this) }
}

override val functions: List<FunctionReference.Descriptor> by lazy(NONE) {
override val functions: List<MemberFunctionReference.Descriptor> by lazy(NONE) {
clazz.unsubstitutedMemberScope
.getContributedDescriptors(kindFilter = DescriptorKindFilter.FUNCTIONS)
.filterIsInstance<FunctionDescriptor>()
Expand All @@ -255,7 +255,7 @@ public sealed class ClassReference : Comparable<ClassReference>, AnnotatedRefere
clazz.annotations.map { it.toAnnotationReference(this, module) }
}

override val properties: List<PropertyReference.Descriptor> by lazy(NONE) {
override val properties: List<MemberPropertyReference.Descriptor> by lazy(NONE) {
clazz.unsubstitutedMemberScope
.getDescriptorsFiltered(kindFilter = DescriptorKindFilter.VARIABLES)
.filterIsInstance<PropertyDescriptor>()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,172 +1,55 @@
package com.squareup.anvil.compiler.internal.reference

import com.squareup.anvil.annotations.ExperimentalAnvilApi
import com.squareup.anvil.compiler.api.AnvilCompilationException
import com.squareup.anvil.compiler.internal.reference.FunctionReference.Descriptor
import com.squareup.anvil.compiler.internal.reference.FunctionReference.Psi
import com.squareup.anvil.compiler.internal.reference.Visibility.INTERNAL
import com.squareup.anvil.compiler.internal.reference.Visibility.PRIVATE
import com.squareup.anvil.compiler.internal.reference.Visibility.PROTECTED
import com.squareup.anvil.compiler.internal.reference.Visibility.PUBLIC
import com.squareup.anvil.compiler.internal.requireFqName
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality.ABSTRACT
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.ABSTRACT_KEYWORD
import org.jetbrains.kotlin.lexer.KtTokens.PUBLIC_KEYWORD
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierTypeOrDefault
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import kotlin.LazyThreadSafetyMode.NONE

/**
* Used to create a common type between [KtNamedFunction] class references and
* [FunctionDescriptor] references, to streamline parsing.
*/
@ExperimentalAnvilApi
public sealed class FunctionReference : AnnotatedReference, FunctionalReference {
public sealed interface FunctionReference {
public val fqName: FqName
public val name: String get() = fqName.shortName().asString()

public abstract val declaringClass: ClassReference
public val module: AnvilModuleDescriptor

public override val module: AnvilModuleDescriptor get() = declaringClass.module
public val parameters: List<ParameterReference>

protected abstract val returnType: TypeReference?
public fun returnTypeOrNull(): TypeReference?
public fun returnType(): TypeReference = returnTypeOrNull()
?: throw AnvilCompilationExceptionFunctionReference(
functionReference = this,
message = "Unable to get the return type for function $fqName."
)

public override fun returnTypeOrNull(): TypeReference? = returnType
public fun visibility(): Visibility

public abstract fun isAbstract(): Boolean
public abstract fun isConstructor(): Boolean
public fun resolveGenericReturnTypeOrNull(
implementingClass: ClassReference
): ClassReference? {
return returnType
?.resolveGenericTypeOrNull(implementingClass)
?.asClassReferenceOrNull()
public sealed interface Psi : FunctionReference {
public val function: KtFunction
}

public fun resolveGenericReturnType(implementingClass: ClassReference): ClassReference =
resolveGenericReturnTypeOrNull(implementingClass)
?: throw AnvilCompilationExceptionFunctionalReference(
functionalReference = this,
message = "Unable to resolve return type for function $fqName with the implementing " +
"class ${implementingClass.fqName}."
)

override fun toString(): String = "$fqName()"

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is FunctionReference) return false

if (fqName != other.fqName) return false

return true
}

override fun hashCode(): Int {
return fqName.hashCode()
}

public class Psi internal constructor(
public override val function: KtFunction,
override val declaringClass: ClassReference.Psi,
override val fqName: FqName
) : FunctionReference(), FunctionalReference.Psi {

override val annotations: List<AnnotationReference.Psi> by lazy(NONE) {
function.annotationEntries.map {
it.toAnnotationReference(declaringClass = null, module)
}
}

override val returnType: TypeReference.Psi? by lazy(NONE) {
function.typeReference?.toTypeReference(declaringClass, module)
}

override val parameters: List<ParameterReference.Psi> by lazy(NONE) {
function.valueParameters.map { it.toParameterReference(this) }
}

override fun isAbstract(): Boolean =
function.hasModifier(ABSTRACT_KEYWORD) ||
(declaringClass.isInterface() && !function.hasBody())

override fun isConstructor(): Boolean = function is KtConstructor<*>

override fun visibility(): Visibility {
return when (val visibility = function.visibilityModifierTypeOrDefault()) {
PUBLIC_KEYWORD -> PUBLIC
KtTokens.INTERNAL_KEYWORD -> INTERNAL
KtTokens.PROTECTED_KEYWORD -> PROTECTED
KtTokens.PRIVATE_KEYWORD -> PRIVATE
else -> throw AnvilCompilationExceptionClassReference(
classReference = declaringClass,
message = "Couldn't get visibility $visibility for function $fqName."
)
}
}
public sealed interface Descriptor : FunctionReference {
public val function: FunctionDescriptor
}

public class Descriptor internal constructor(
public override val function: FunctionDescriptor,
override val declaringClass: ClassReference.Descriptor,
override val fqName: FqName = function.fqNameSafe
) : FunctionReference(), FunctionalReference.Descriptor {

override val annotations: List<AnnotationReference.Descriptor> by lazy(NONE) {
function.annotations.map {
it.toAnnotationReference(declaringClass = null, module)
}
}

override val parameters: List<ParameterReference.Descriptor> by lazy(NONE) {
function.valueParameters.map { it.toParameterReference(this) }
}

override val returnType: TypeReference.Descriptor? by lazy(NONE) {
function.returnType?.toTypeReference(declaringClass, module)
}

override fun isAbstract(): Boolean = function.modality == ABSTRACT

override fun isConstructor(): Boolean = function is ClassConstructorDescriptor

override fun visibility(): Visibility {
return when (val visibility = function.visibility) {
DescriptorVisibilities.PUBLIC -> PUBLIC
DescriptorVisibilities.INTERNAL -> INTERNAL
DescriptorVisibilities.PROTECTED -> PROTECTED
DescriptorVisibilities.PRIVATE -> PRIVATE
else -> throw AnvilCompilationExceptionClassReference(
classReference = declaringClass,
message = "Couldn't get visibility $visibility for function $fqName."
)
}
}
}
}

@ExperimentalAnvilApi
public fun KtFunction.toFunctionReference(
declaringClass: ClassReference.Psi
): Psi {
val fqName = if (this is KtConstructor<*>) {
declaringClass.fqName.child(Name.identifier("<init>"))
} else {
requireFqName()
}

return Psi(this, declaringClass, fqName)
}

@ExperimentalAnvilApi
public fun FunctionDescriptor.toFunctionReference(
declaringClass: ClassReference.Descriptor,
): Descriptor {
return Descriptor(this, declaringClass)
@Suppress("FunctionName")
public fun AnvilCompilationExceptionFunctionReference(
functionReference: FunctionReference,
message: String,
cause: Throwable? = null
): AnvilCompilationException = when (functionReference) {
is Psi -> AnvilCompilationException(
element = functionReference.function,
message = message,
cause = cause
)
is Descriptor -> AnvilCompilationException(
functionDescriptor = functionReference.function,
message = message,
cause = cause
)
}

This file was deleted.

Loading

0 comments on commit f96e305

Please sign in to comment.