saveourtool / diktat

Strict coding standard for Kotlin and a custom set of rules for detecting code smells, code style issues and bugs
https://diktat.saveourtool.com
MIT License
519 stars 39 forks source link

Refactor `fun isPairPropertyBackingField` using `PSI` #1822

Closed diphtongue closed 7 months ago

diphtongue commented 8 months ago

    @Suppress("CyclomaticComplexMethod") 
    internal fun isPairPropertyBackingField(propertyNode: ASTNode?, backingFieldNode: ASTNode?): Boolean {
        val node = propertyNode ?: backingFieldNode
        val propertyListNullable = (node?.treeParent?.getAllChildrenWithType(PROPERTY)) ?: return false
        val propertyList: List<ASTNode> = propertyListNullable
        val nodeType = node.getFirstChildWithType(KtNodeTypes.TYPE_REFERENCE)
        val nodeNullableType = nodeType?.getFirstChildWithType(KtNodeTypes.NULLABLE_TYPE)
        val nodeName = node.getFirstChildWithType(IDENTIFIER)?.text 

        val matchingNode = propertyList.find {pairNode ->
            val propertyType = pairNode.getFirstChildWithType(KtNodeTypes.TYPE_REFERENCE)
            // check that property and backing field has same type
            val sameType = nodeType?.text == propertyType?.text
            // check that property USER_TYPE is same as backing field NULLABLE_TYPE
            val sameTypeWithNullable = propertyType?.getFirstChildWithType(KtNodeTypes.USER_TYPE)?.text ==
                nodeNullableType?.getFirstChildWithType(KtNodeTypes.USER_TYPE)?.text
            // check matching names
            val propertyName = pairNode.getFirstChildWithType(IDENTIFIER)?.text
            val matchingNames = propertyNode?.let { nodeName == propertyName?.drop(1) } ?: run { nodeName?.drop(1) == propertyName }

            val isPrivate = propertyNode?.let { pairNode.isPrivate() } ?: run { node.isPrivate() }
            val noSetterGetterBackingField = propertyNode?.let { !pairNode.hasSetterOrGetter() } ?: run { !node.hasSetterOrGetter() }
            val hasSetterOrGetterProperty = propertyNode?.let { node.hasSetterOrGetter() } ?: run { pairNode.hasSetterOrGetter() }

            matchingNames && (sameType || sameTypeWithNullable) && isPrivate &&
                noSetterGetterBackingField && hasSetterOrGetterProperty
        }
        return matchingNode?.let { true } ?: false
}