diff options
| author | Ignat Beresnev <ignat.beresnev@jetbrains.com> | 2022-05-31 15:34:37 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-31 15:34:37 +0200 |
| commit | 623cf222ca2ac5e8b9628af5927956ecb6d44d1e (patch) | |
| tree | a995477a569dd27b99d24bd901bdcc024f4f7dd0 /plugins/base/src/main/kotlin/translators/psi | |
| parent | 8913c97b25ebf5061ea367129544d7e5186a738d (diff) | |
| download | dokka-623cf222ca2ac5e8b9628af5927956ecb6d44d1e.tar.gz dokka-623cf222ca2ac5e8b9628af5927956ecb6d44d1e.tar.bz2 dokka-623cf222ca2ac5e8b9628af5927956ecb6d44d1e.zip | |
Fix gathering inherited properties (#2481)
* Fix gathering inherited properties in PSI
* Refacotr KaJ transformer. Change wrapping TagWrapper for getters and setters.
* Add logic to merge inherited properties in kotlin from java sources.
* Remove getters and setters from JvmField properties for DObject, DEnum, DInterface in KaJ.
* Unify InheritedMember DRI logic.
* Fix gathering docs obtained from inheriting java sources in descriptors
* Apply requested changes.
* Resolve rebase conflicts
* Use 221 for qodana analysis
* Move accessors generation into DefaultDescriptorToDocumentableTranslator
* Fix special "is" case for accessors and refactor logic in general
* Remove ambiguous import after rebasing
* Remove unused imports and format code
* Apply review comment suggestions
* Preserve previously lost accessor lookalikes
* Extract a variable and correct a typo
Co-authored-by: Andrzej Ratajczak <andrzej.ratajczak98@gmail.com>
Diffstat (limited to 'plugins/base/src/main/kotlin/translators/psi')
| -rw-r--r-- | plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt | 406 | ||||
| -rw-r--r-- | plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt | 58 |
2 files changed, 300 insertions, 164 deletions
diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index f9199154..5b30543e 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -25,7 +25,6 @@ import org.jetbrains.dokka.links.* import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.AnnotationTarget import org.jetbrains.dokka.model.Nullable -import org.jetbrains.dokka.model.TypeConstructor import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.Param import org.jetbrains.dokka.model.properties.PropertyContainer @@ -87,14 +86,14 @@ class DefaultPsiToDocumentableTranslator( ) DModule( - context.configuration.moduleName, - psiFiles.parallelMapNotNull { it.safeAs<PsiJavaFile>() }.groupBy { it.packageName }.toList() + name = context.configuration.moduleName, + packages = psiFiles.parallelMapNotNull { it.safeAs<PsiJavaFile>() }.groupBy { it.packageName }.toList() .parallelMap { (packageName: String, psiFiles: List<PsiJavaFile>) -> docParser.parsePackage(packageName, psiFiles) }, - emptyMap(), - null, - setOf(sourceSet) + documentation = emptyMap(), + expectPresentInSet = null, + sourceSets = setOf(sourceSet) ) } } @@ -122,6 +121,9 @@ class DefaultPsiToDocumentableTranslator( private val PsiMethod.hash: Int get() = "$returnType $name$parameterList".hashCode() + private val PsiField.hash: Int + get() = "$type $name".hashCode() + private val PsiClassType.shouldBeIgnored: Boolean get() = isClass("java.lang.Enum") || isClass("java.lang.Object") @@ -148,19 +150,19 @@ class DefaultPsiToDocumentableTranslator( val annotations = packageInfo?.packageStatement?.annotationList?.annotations DPackage( - dri, - emptyList(), - emptyList(), - psiFiles.parallelMap { psiFile -> + dri = dri, + functions = emptyList(), + properties = emptyList(), + classlikes = psiFiles.parallelMap { psiFile -> coroutineScope { psiFile.classes.asIterable().parallelMap { parseClasslike(it, dri) } } }.flatten(), - emptyList(), - documentation, - null, - setOf(sourceSetData), - PropertyContainer.withAll( + typealiases = emptyList(), + documentation = documentation, + expectPresentInSet = null, + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( annotations?.toList().orEmpty().toListOfAnnotations().toSourceSetDependent().toAnnotations() ) ) @@ -171,10 +173,16 @@ class DefaultPsiToDocumentableTranslator( val dri = parent.withClass(name.toString()) val superMethodsKeys = hashSetOf<Int>() val superMethods = mutableListOf<Pair<PsiMethod, DRI>>() + val superFieldsKeys = hashSetOf<Int>() + val superFields = mutableListOf<Pair<PsiField, DRI>>() methods.asIterable().parallelForEach { superMethodsKeys.add(it.hash) } /** - * Caution! This method mutates superMethodsKeys and superMethods + * Caution! This method mutates + * - superMethodsKeys + * - superMethods + * - superFieldsKeys + * - superKeys */ fun Array<PsiClassType>.getSuperTypesPsiClasses(): List<Pair<PsiClass, JavaClassKindTypes>> { forEach { type -> @@ -189,6 +197,13 @@ class DefaultPsiToDocumentableTranslator( superMethods.add(Pair(method, definedAt)) } } + it.fields.forEach { field -> + val hash = field.hash + if (!superFieldsKeys.contains(hash)) { + superFieldsKeys.add(hash) + superFields.add(Pair(field, definedAt)) + } + } } } return filter { !it.shouldBeIgnored }.mapNotNull { supertypePsi -> @@ -223,24 +238,60 @@ class DefaultPsiToDocumentableTranslator( } val ancestry: AncestryNode = traversePsiClassForAncestorsAndInheritedMembers(this) - val (regularFunctions, accessors) = splitFunctionsAndAccessors() + + val (regularFunctions, accessors) = splitFunctionsAndAccessors(psi.fields, psi.methods) + val (regularSuperFunctions, superAccessors) = splitFunctionsAndAccessors( + fields = superFields.map { it.first }.toTypedArray(), + methods = superMethods.map { it.first }.toTypedArray() + ) + + val regularSuperFunctionsKeys = regularSuperFunctions.map { it.hash }.toSet() + val regularSuperFunctionsWithDRI = superMethods.filter { it.first.hash in regularSuperFunctionsKeys } + + val superAccessorsWithDRI = superAccessors.mapValues { (field, methods) -> + val containsJvmField = field.annotations.mapNotNull { it.toAnnotation() }.any { it.isJvmField() } + if (containsJvmField) { + emptyList() + } else { + methods.mapNotNull { method -> superMethods.find { it.first.hash == method.hash } } + } + } + val overridden = regularFunctions.flatMap { it.findSuperMethods().toList() } val documentation = javadocParser.parseDocumentation(this).toSourceSetDependent() val allFunctions = async { - regularFunctions.parallelMapNotNull { + val parsedRegularFunctions = regularFunctions.parallelMapNotNull { if (!it.isConstructor) parseFunction( it, parentDRI = dri ) else null - } + superMethods.filter { it.first !in overridden }.parallelMap { parseFunction(it.first, inheritedFrom = it.second) } + } + val parsedSuperFunctions = regularSuperFunctionsWithDRI + .filter { it.first !in overridden } + .parallelMap { parseFunction(it.first, inheritedFrom = it.second) } + + parsedRegularFunctions + parsedSuperFunctions + } + val allFields = async { + val parsedFields = fields.toList().parallelMapNotNull { + parseField(it, accessors[it].orEmpty()) + } + val parsedSuperFields = superFields.parallelMapNotNull { (field, dri) -> + parseFieldWithInheritingAccessors( + field, + superAccessorsWithDRI[field].orEmpty(), + inheritedFrom = dri + ) + } + parsedFields + parsedSuperFields } val source = PsiDocumentableSource(this).toSourceSetDependent() val classlikes = async { innerClasses.asIterable().parallelMap { parseClasslike(it, dri) } } val visibility = getVisibility().toSourceSetDependent() val ancestors = (listOfNotNull(ancestry.superclass?.let { - it.typeConstructor.let { + it.typeConstructor.let { typeConstructor -> TypeConstructorWithKind( - it, + typeConstructor, JavaClassKindTypes.CLASS ) } @@ -251,103 +302,103 @@ class DefaultPsiToDocumentableTranslator( when { isAnnotationType -> DAnnotation( - name.orEmpty(), - dri, - documentation, - null, - source, - allFunctions.await(), - fields.mapNotNull { parseField(it, accessors[it].orEmpty()) }, - classlikes.await(), - visibility, - null, - constructors.map { parseFunction(it, true) }, - mapTypeParameters(dri), - setOf(sourceSetData), - false, - PropertyContainer.withAll( + name = name.orEmpty(), + dri = dri, + documentation = documentation, + expectPresentInSet = null, + sources = source, + functions = allFunctions.await(), + properties = allFields.await(), + classlikes = classlikes.await(), + visibility = visibility, + companion = null, + constructors = constructors.map { parseFunction(it, true) }, + generics = mapTypeParameters(dri), + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations() ) ) isEnum -> DEnum( - dri, - name.orEmpty(), - fields.filterIsInstance<PsiEnumConstant>().map { entry -> + dri = dri, + name = name.orEmpty(), + entries = fields.filterIsInstance<PsiEnumConstant>().map { entry -> DEnumEntry( - dri.withClass(entry.name).withEnumEntryExtra(), - entry.name, - javadocParser.parseDocumentation(entry).toSourceSetDependent(), - null, - emptyList(), - emptyList(), - emptyList(), - setOf(sourceSetData), - PropertyContainer.withAll( + dri = dri.withClass(entry.name).withEnumEntryExtra(), + name = entry.name, + documentation = javadocParser.parseDocumentation(entry).toSourceSetDependent(), + expectPresentInSet = null, + functions = emptyList(), + properties = emptyList(), + classlikes = emptyList(), + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations() ) ) }, - documentation, - null, - source, - allFunctions.await(), - fields.filter { it !is PsiEnumConstant }.map { parseField(it, accessors[it].orEmpty()) }, - classlikes.await(), - visibility, - null, - constructors.map { parseFunction(it, true) }, - ancestors, - setOf(sourceSetData), - false, - PropertyContainer.withAll( + documentation = documentation, + expectPresentInSet = null, + sources = source, + functions = allFunctions.await(), + properties = fields.filter { it !is PsiEnumConstant }.map { parseField(it, accessors[it].orEmpty()) }, + classlikes = classlikes.await(), + visibility = visibility, + companion = null, + constructors = constructors.map { parseFunction(it, true) }, + supertypes = ancestors, + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations() ) ) isInterface -> DInterface( - dri, - name.orEmpty(), - documentation, - null, - source, - allFunctions.await(), - fields.mapNotNull { parseField(it, accessors[it].orEmpty()) }, - classlikes.await(), - visibility, - null, - mapTypeParameters(dri), - ancestors, - setOf(sourceSetData), - false, - PropertyContainer.withAll( + dri = dri, + name = name.orEmpty(), + documentation = documentation, + expectPresentInSet = null, + sources = source, + functions = allFunctions.await(), + properties = allFields.await(), + classlikes = classlikes.await(), + visibility = visibility, + companion = null, + generics = mapTypeParameters(dri), + supertypes = ancestors, + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations() ) ) else -> DClass( - dri, - name.orEmpty(), - constructors.map { parseFunction(it, true) }, - allFunctions.await(), - fields.mapNotNull { parseField(it, accessors[it].orEmpty()) }, - classlikes.await(), - source, - visibility, - null, - mapTypeParameters(dri), - ancestors, - documentation, - null, - modifiers, - setOf(sourceSetData), - false, - PropertyContainer.withAll( + dri = dri, + name = name.orEmpty(), + constructors = constructors.map { parseFunction(it, true) }, + functions = allFunctions.await(), + properties = allFields.await(), + classlikes = classlikes.await(), + sources = source, + visibility = visibility, + companion = null, + generics = mapTypeParameters(dri), + supertypes = ancestors, + documentation = documentation, + expectPresentInSet = null, + modifier = modifiers, + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = PropertyContainer.withAll( implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations(), @@ -372,40 +423,40 @@ class DefaultPsiToDocumentableTranslator( } ?: DRI.from(psi) val docs = javadocParser.parseDocumentation(psi) return DFunction( - dri, - psi.name, - isConstructor, - psi.parameterList.parameters.map { psiParameter -> + dri = dri, + name = psi.name, + isConstructor = isConstructor, + parameters = psi.parameterList.parameters.map { psiParameter -> DParameter( - dri.copy(target = dri.target.nextTarget()), - psiParameter.name, - DocumentationNode( + dri = dri.copy(target = dri.target.nextTarget()), + name = psiParameter.name, + documentation = DocumentationNode( listOfNotNull(docs.firstChildOfTypeOrNull<Param> { it.name == psiParameter.name }) ).toSourceSetDependent(), - null, - getBound(psiParameter.type), - setOf(sourceSetData), - PropertyContainer.withAll( + expectPresentInSet = null, + type = getBound(psiParameter.type), + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( psiParameter.annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations() ) ) }, - docs.toSourceSetDependent(), - null, - PsiDocumentableSource(psi).toSourceSetDependent(), - psi.getVisibility().toSourceSetDependent(), - psi.returnType?.let { getBound(type = it) } ?: Void, - psi.mapTypeParameters(dri), - null, - psi.getModifier().toSourceSetDependent(), - setOf(sourceSetData), - false, - psi.additionalExtras().let { + documentation = docs.toSourceSetDependent(), + expectPresentInSet = null, + sources = PsiDocumentableSource(psi).toSourceSetDependent(), + visibility = psi.getVisibility().toSourceSetDependent(), + type = psi.returnType?.let { getBound(type = it) } ?: Void, + generics = psi.mapTypeParameters(dri), + receiver = null, + modifier = psi.getModifier().toSourceSetDependent(), + sourceSets = setOf(sourceSetData), + isExpectActual = false, + extra = psi.additionalExtras().let { PropertyContainer.withAll( - InheritedMember(inheritedFrom.toSourceSetDependent()), + inheritedFrom?.let { InheritedMember(it.toSourceSetDependent()) }, it.toSourceSetDependent().toAdditionalModifiers(), (psi.annotations.toList() .toListOfAnnotations() + it.toListOfAnnotations()).toSourceSetDependent() @@ -437,6 +488,20 @@ class DefaultPsiToDocumentableTranslator( Annotations.Annotation(DRI("kotlin.jvm", "JvmStatic"), emptyMap()) } + /** + * Workaround for getting JvmField Kotlin annotation in PSIs + */ + private fun Collection<PsiAnnotation>.findJvmFieldAnnotation(): Annotations.Annotation? { + val anyJvmFieldAnnotation = this.any { + it.qualifiedName == "$JVM_FIELD_PACKAGE_NAME.$JVM_FIELD_CLASS_NAMES" + } + return if (anyJvmFieldAnnotation) { + Annotations.Annotation(DRI(JVM_FIELD_PACKAGE_NAME, JVM_FIELD_CLASS_NAMES), emptyMap()) + } else { + null + } + } + private fun <T : AnnotationTarget> PsiTypeParameter.annotations(): PropertyContainer<T> = this.annotations.toList().toListOfAnnotations().annotations() private fun <T : AnnotationTarget> PsiType.annotations(): PropertyContainer<T> = this.annotations.toList().toListOfAnnotations().annotations() @@ -521,14 +586,14 @@ class DefaultPsiToDocumentableTranslator( } return typeParameters.map { type -> DTypeParameter( - dri.copy(target = dri.target.nextTarget()), - type.name.orEmpty(), - null, - javadocParser.parseDocumentation(type).toSourceSetDependent(), - null, - mapBounds(type.bounds), - setOf(sourceSetData), - PropertyContainer.withAll( + dri = dri.copy(target = dri.target.nextTarget()), + name = type.name.orEmpty(), + presentableName = null, + documentation = javadocParser.parseDocumentation(type).toSourceSetDependent(), + expectPresentInSet = null, + bounds = mapBounds(type.bounds), + sourceSets = setOf(sourceSetData), + extra = PropertyContainer.withAll( type.annotations.toList().toListOfAnnotations().toSourceSetDependent() .toAnnotations() ) @@ -536,53 +601,66 @@ class DefaultPsiToDocumentableTranslator( } } - private fun PsiMethod.getPropertyNameForFunction() = - getAnnotation(DescriptorUtils.JVM_NAME.asString())?.findAttributeValue("name")?.text - ?: when { - JvmAbi.isGetterName(name) -> propertyNameByGetMethodName(Name.identifier(name))?.asString() - JvmAbi.isSetterName(name) -> propertyNamesBySetMethodName(Name.identifier(name)).firstOrNull() - ?.asString() - else -> null - } + private fun parseFieldWithInheritingAccessors( + psi: PsiField, + accessors: List<Pair<PsiMethod, DRI>>, + inheritedFrom: DRI + ): DProperty { + val getter = accessors + .firstOrNull { (method, _) -> method.isGetterFor(psi) } + ?.let { (method, dri) -> parseFunction(method, inheritedFrom = dri) } + + val setter = accessors + .firstOrNull { (method, _) -> method.isSetterFor(psi) } + ?.let { (method, dri) -> parseFunction(method, inheritedFrom = dri) } + + return parseField( + psi = psi, + getter = getter, + setter = setter, + inheritedFrom = inheritedFrom + ) + } - private fun PsiClass.splitFunctionsAndAccessors(): Pair<MutableList<PsiMethod>, MutableMap<PsiField, MutableList<PsiMethod>>> { - val fieldNames = fields.associateBy { it.name } - val accessors = mutableMapOf<PsiField, MutableList<PsiMethod>>() - val regularMethods = mutableListOf<PsiMethod>() - methods.forEach { method -> - val field = method.getPropertyNameForFunction()?.let { name -> fieldNames[name] } - if (field != null) { - accessors.getOrPut(field, ::mutableListOf).add(method) - } else { - regularMethods.add(method) - } - } - return regularMethods to accessors + private fun parseField(psi: PsiField, accessors: List<PsiMethod>, inheritedFrom: DRI? = null): DProperty { + val getter = accessors.firstOrNull { it.isGetterFor(psi) }?.let { parseFunction(it) } + val setter = accessors.firstOrNull { it.isSetterFor(psi) }?.let { parseFunction(it) } + return parseField( + psi = psi, + getter = getter, + setter = setter, + inheritedFrom = inheritedFrom + ) } - private fun parseField(psi: PsiField, accessors: List<PsiMethod>): DProperty { + private fun parseField(psi: PsiField, getter: DFunction?, setter: DFunction?, inheritedFrom: DRI? = null): DProperty { val dri = DRI.from(psi) return DProperty( - dri, - psi.name, - javadocParser.parseDocumentation(psi).toSourceSetDependent(), - null, - PsiDocumentableSource(psi).toSourceSetDependent(), - psi.getVisibility().toSourceSetDependent(), - getBound(psi.type), - null, - accessors.firstOrNull { it.hasParameters() }?.let { parseFunction(it) }, - accessors.firstOrNull { it.returnType == psi.type }?.let { parseFunction(it) }, - psi.getModifier().toSourceSetDependent(), - setOf(sourceSetData), - emptyList(), - false, - psi.additionalExtras().let { + dri = dri, + name = psi.name, + documentation = javadocParser.parseDocumentation(psi).toSourceSetDependent(), + expectPresentInSet = null, + sources = PsiDocumentableSource(psi).toSourceSetDependent(), + visibility = psi.getVisibility().toSourceSetDependent(), + type = getBound(psi.type), + receiver = null, + setter = setter, + getter = getter, + modifier = psi.getModifier().toSourceSetDependent(), + sourceSets = setOf(sourceSetData), + generics = emptyList(), + isExpectActual = false, + extra = psi.additionalExtras().let { + val psiAnnotations = psi.annotations.toList() + val parsedAnnotations = psiAnnotations.toListOfAnnotations() + val extraModifierAnnotations = it.toListOfAnnotations() + val jvmFieldAnnotation = psiAnnotations.findJvmFieldAnnotation() + val annotations = parsedAnnotations + extraModifierAnnotations + listOfNotNull(jvmFieldAnnotation) + PropertyContainer.withAll( + inheritedFrom?.let { inheritedFrom -> InheritedMember(inheritedFrom.toSourceSetDependent()) }, it.toSourceSetDependent().toAdditionalModifiers(), - (psi.annotations.toList() - .toListOfAnnotations() + it.toListOfAnnotations()).toSourceSetDependent() - .toAnnotations() + annotations.toSourceSetDependent().toAnnotations() ) } ) diff --git a/plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt b/plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt new file mode 100644 index 00000000..c2ab8c03 --- /dev/null +++ b/plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt @@ -0,0 +1,58 @@ +package org.jetbrains.dokka.base.translators.psi + +import com.intellij.psi.PsiField +import com.intellij.psi.PsiMethod +import org.jetbrains.dokka.base.translators.firstNotNullOfOrNull +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName +import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils + + +internal data class PsiFunctionsHolder( + val regularFunctions: List<PsiMethod>, + val accessors: Map<PsiField, List<PsiMethod>> +) + +internal fun splitFunctionsAndAccessors(fields: Array<PsiField>, methods: Array<PsiMethod>): PsiFunctionsHolder { + val fieldsByName = fields.associateBy { it.name } + val regularFunctions = mutableListOf<PsiMethod>() + val accessors = mutableMapOf<PsiField, MutableList<PsiMethod>>() + methods.forEach { method -> + val possiblePropertyNamesForFunction = method.getPossiblePropertyNamesForFunction() + val field = possiblePropertyNamesForFunction.firstNotNullOfOrNull { fieldsByName[it] } + if (field != null && method.isAccessorFor(field)) { + accessors.getOrPut(field, ::mutableListOf).add(method) + } else { + regularFunctions.add(method) + } + } + return PsiFunctionsHolder(regularFunctions, accessors) +} + +internal fun PsiMethod.getPossiblePropertyNamesForFunction(): List<String> { + val jvmName = getAnnotation(DescriptorUtils.JVM_NAME.asString())?.findAttributeValue("name")?.text + return jvmName?.let { listOf(jvmName) } + ?: when { + JvmAbi.isGetterName(name) -> listOfNotNull( + propertyNameByGetMethodName(Name.identifier(name))?.asString() + ) + JvmAbi.isSetterName(name) -> { + propertyNamesBySetMethodName(Name.identifier(name)).map { it.asString() } + } + else -> listOf() + } +} + +internal fun PsiMethod.isAccessorFor(field: PsiField): Boolean { + return this.isGetterFor(field) || this.isSetterFor(field) +} + +internal fun PsiMethod.isGetterFor(field: PsiField): Boolean { + return this.returnType == field.type && !this.hasParameters() +} + +internal fun PsiMethod.isSetterFor(field: PsiField): Boolean { + return parameterList.getParameter(0)?.type == field.type +} |
