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

org.jetbrains.kotlin.resolve.calls.tasks.CallableDescriptorCollectors.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2015 JetBrains s.r.o.
 *
 * 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.
 */

package org.jetbrains.kotlin.resolve.calls.tasks.collectors

import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils.isStaticNestedClass
import org.jetbrains.kotlin.resolve.LibrarySourceHacks
import org.jetbrains.kotlin.resolve.calls.tasks.createSynthesizedInvokes
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
import org.jetbrains.kotlin.resolve.descriptorUtil.hasClassObjectType
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent
import org.jetbrains.kotlin.resolve.scopes.utils.getLocalVariable
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.utils.singletonOrEmptyList

public interface CallableDescriptorCollector {

    public fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection

    public fun getNonExtensionsByName(scope: JetScope, name: Name, location: LookupLocation): Collection

    public fun getMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection

    public fun getStaticMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection

    public fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, location: LookupLocation): Collection
}

private fun  CallableDescriptorCollector.withDefaultFilter() = filtered { !LibrarySourceHacks.shouldSkip(it) }

private val FUNCTIONS_COLLECTOR = FunctionCollector.withDefaultFilter()
private val VARIABLES_COLLECTOR = VariableCollector.withDefaultFilter()
private val PROPERTIES_COLLECTOR = PropertyCollector.withDefaultFilter()

public class CallableDescriptorCollectors(val collectors: List>) :
        Iterable> {
    override fun iterator(): Iterator> = collectors.iterator()

    @Suppress("UNCHECKED_CAST")
    companion object {
        public val FUNCTIONS_AND_VARIABLES: CallableDescriptorCollectors =
                CallableDescriptorCollectors(listOf(
                        FUNCTIONS_COLLECTOR as CallableDescriptorCollector,
                        VARIABLES_COLLECTOR as CallableDescriptorCollector
                ))
        public val FUNCTIONS: CallableDescriptorCollectors =
                CallableDescriptorCollectors(listOf(FUNCTIONS_COLLECTOR as CallableDescriptorCollector))
        public val VARIABLES: CallableDescriptorCollectors = CallableDescriptorCollectors(listOf(VARIABLES_COLLECTOR))
        public val PROPERTIES: CallableDescriptorCollectors = CallableDescriptorCollectors(listOf(PROPERTIES_COLLECTOR))
    }
}

public fun  CallableDescriptorCollectors.filtered(filter: (D) -> Boolean): CallableDescriptorCollectors =
        CallableDescriptorCollectors(this.collectors.map { it.filtered(filter) })

private object FunctionCollector : CallableDescriptorCollector {
    override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection {
        return lexicalScope.collectAllFromMeAndParent {
            if (it.ownerDescriptor is FunctionDescriptor) {
                it.getDeclaredFunctions(name, location).filter { it.extensionReceiverParameter == null } +
                    getConstructors(it.getDeclaredClassifier(name, location))
            }
            else {
                emptyList()
            }
        }
    }

    override fun getNonExtensionsByName(scope: JetScope, name: Name, location: LookupLocation): Collection {
        return scope.getFunctions(name, location).filter { it.extensionReceiverParameter == null } + getConstructors(scope, name, location)
    }

    override fun getMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
        val receiverScope = receiver.memberScope
        val members = receiverScope.getFunctions(name, location)
        val constructors = getConstructors(receiverScope, name, location, { !isStaticNestedClass(it) })

        if (name == OperatorConventions.INVOKE && KotlinBuiltIns.isExtensionFunctionType(receiver)) {
            // If we're looking for members of an extension function type, we ignore the non-extension "invoke"s
            // that originate from the Function{n} class and only consider the synthesized "invoke" extensions.
            // Otherwise confusing errors will be reported because the non-extension here beats the extension
            // (because declarations beat synthesized members)
            val (candidatesForReplacement, irrelevantInvokes) =
                    members.partition { it is FunctionInvokeDescriptor && it.valueParameters.isNotEmpty() }
            return createSynthesizedInvokes(candidatesForReplacement) + irrelevantInvokes + constructors
        }

        return members + constructors
    }

    override fun getStaticMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
        return getConstructors(receiver.memberScope, name, location, { isStaticNestedClass(it) })
    }

    override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, location: LookupLocation): Collection {
        val functions = scope.getFunctions(name, location)
        val (extensions, nonExtensions) = functions.partition { it.extensionReceiverParameter != null }
        val syntheticExtensions = scope.getSyntheticExtensionFunctions(receiverTypes, name, location)

        if (name == OperatorConventions.INVOKE) {
            // Create synthesized "invoke" extensions for each non-extension "invoke" found in the scope
            return extensions + createSynthesizedInvokes(nonExtensions) + syntheticExtensions
        }

        return extensions + syntheticExtensions
    }

    private fun getConstructors(
            scope: JetScope, name: Name,
            location: LookupLocation,
            filterClassPredicate: (ClassDescriptor) -> Boolean = { true }
    ): Collection {
        val classifier = scope.getClassifier(name, location)
        return getConstructors(classifier, filterClassPredicate)
    }

    private fun getConstructors(
            classifier: ClassifierDescriptor?,
            filterClassPredicate: (ClassDescriptor) -> Boolean = { true }
    ): Collection {
        if (classifier !is ClassDescriptor || ErrorUtils.isError(classifier) || !filterClassPredicate(classifier)
            // Constructors of singletons shouldn't be callable from the code
            || classifier.kind.isSingleton) {
            return listOf()
        }
        return classifier.constructors
    }

    override fun toString() = "FUNCTIONS"
}

private object VariableCollector : CallableDescriptorCollector {
    override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection {
        return listOfNotNull(lexicalScope.getLocalVariable(name))
    }

    private fun getFakeDescriptorForObject(scope: JetScope, name: Name, location: LookupLocation): VariableDescriptor? {
        val classifier = scope.getClassifier(name, location)
        if (classifier !is ClassDescriptor || !classifier.hasClassObjectType) return null

        return FakeCallableDescriptorForObject(classifier)
    }

    override fun getNonExtensionsByName(scope: JetScope, name: Name, location: LookupLocation): Collection {
        val localVariable = scope.getLocalVariable(name)
        if (localVariable != null) {
            return setOf(localVariable)
        }
        val properties = scope.getProperties(name, location).filter { it.extensionReceiverParameter == null }
        val fakeDescriptor = getFakeDescriptorForObject(scope, name, location)
        return if (fakeDescriptor != null) properties + fakeDescriptor else properties
    }

    override fun getMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
        val memberScope = receiver.memberScope
        val properties = memberScope.getProperties(name, location)
        val fakeDescriptor = getFakeDescriptorForObject(memberScope, name, location)
        return if (fakeDescriptor != null) properties + fakeDescriptor else properties
    }

    override fun getStaticMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
        return listOf()
    }

    override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, location: LookupLocation): Collection {
        // property may have an extension function type, we check the applicability later to avoid an early computing of deferred types
        return scope.getLocalVariable(name).singletonOrEmptyList() +
               scope.getProperties(name, location) +
               scope.getSyntheticExtensionProperties(receiverTypes, name, location)
    }

    override fun toString() = "VARIABLES"
}

private object PropertyCollector : CallableDescriptorCollector {
    private fun filterProperties(variableDescriptors: Collection) =
            variableDescriptors.filter { it is PropertyDescriptor }

    override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection {
        return filterProperties(VARIABLES_COLLECTOR.getLocalNonExtensionsByName(lexicalScope, name, location))
    }

    override fun getNonExtensionsByName(scope: JetScope, name: Name, location: LookupLocation): Collection {
        return filterProperties(VARIABLES_COLLECTOR.getNonExtensionsByName(scope, name, location))
    }

    override fun getMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
        return filterProperties(VARIABLES_COLLECTOR.getMembersByName(receiver, name, location))
    }

    override fun getStaticMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
        return filterProperties(VARIABLES_COLLECTOR.getStaticMembersByName(receiver, name, location))
    }

    override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, location: LookupLocation): Collection {
        return filterProperties(VARIABLES_COLLECTOR.getExtensionsByName(scope, name, receiverTypes, location))
    }

    override fun toString() = "PROPERTIES"
}

private fun  CallableDescriptorCollector.filtered(filter: (D) -> Boolean): CallableDescriptorCollector {
    val delegate = this
    return object : CallableDescriptorCollector {
        override fun getLocalNonExtensionsByName(lexicalScope: LexicalScope, name: Name, location: LookupLocation): Collection {
            return delegate.getLocalNonExtensionsByName(lexicalScope, name, location).filter(filter)
        }

        override fun getNonExtensionsByName(scope: JetScope, name: Name, location: LookupLocation): Collection {
            return delegate.getNonExtensionsByName(scope, name, location).filter(filter)
        }

        override fun getMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
            return delegate.getMembersByName(receiver, name, location).filter(filter)
        }

        override fun getStaticMembersByName(receiver: JetType, name: Name, location: LookupLocation): Collection {
            return delegate.getStaticMembersByName(receiver, name, location).filter(filter)
        }

        override fun getExtensionsByName(scope: JetScope, name: Name, receiverTypes: Collection, location: LookupLocation): Collection {
            return delegate.getExtensionsByName(scope, name, receiverTypes, location).filter(filter)
        }

        override fun toString(): String {
            return delegate.toString()
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy