Extract Function: Approximate non-resolvable types with nearest resolvable supertype when possible

#KT-7120 Fixed
This commit is contained in:
Alexey Sedunov
2015-03-27 13:42:43 +03:00
parent a90d020859
commit eb594a2897
22 changed files with 224 additions and 86 deletions
@@ -0,0 +1,71 @@
/*
* 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.idea.imports
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.*
public val DeclarationDescriptor.importableFqName: FqName?
get() {
val mayBeUnsafe = DescriptorUtils.getFqName(getImportableDescriptor())
return if (mayBeUnsafe.isSafe()) mayBeUnsafe.toSafe() else null
}
public val DeclarationDescriptor.importableFqNameSafe: FqName
get() = DescriptorUtils.getFqNameSafe(getImportableDescriptor())
public fun DeclarationDescriptor.canBeReferencedViaImport(): Boolean {
if (this is PackageViewDescriptor ||
DescriptorUtils.isTopLevelDeclaration(this) ||
(this is CallableDescriptor && DescriptorUtils.isStaticDeclaration(this))) {
return !getName().isSpecial()
}
val parentClass = getContainingDeclaration() as? ClassDescriptor ?: return false
if (!parentClass.canBeReferencedViaImport()) return false
return when (this) {
is ConstructorDescriptor -> !parentClass.isInner() // inner class constructors can't be referenced via import
is ClassDescriptor -> true
else -> false
}
}
public fun JetType.canBeReferencedViaImport(): Boolean {
val descriptor = getConstructor().getDeclarationDescriptor()
return descriptor != null && descriptor.canBeReferencedViaImport()
}
// for cases when class qualifier refers companion object treats it like reference to class itself
public fun JetReferenceExpression.getImportableTargets(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
val targets = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, this]?.let { listOf(it) }
?: bindingContext[BindingContext.REFERENCE_TARGET, this]?.let { listOf(it) }
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, this]
?: listOf()
return targets.map { it.getImportableDescriptor() }.toSet()
}
@@ -20,7 +20,10 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.jvm.kotlinSignature.CollectionClassMapping
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.resolve.scopes.JetScope
import java.util.LinkedHashSet
import org.jetbrains.kotlin.types.typeUtil.substitute
@@ -87,3 +90,19 @@ public fun JetType.nullability(): TypeNullability {
else -> TypeNullability.NOT_NULL
}
}
fun JetType.isResolvableInScope(scope: JetScope?, checkTypeParameters: Boolean): Boolean {
if (canBeReferencedViaImport()) return true
val descriptor = getConstructor().getDeclarationDescriptor()
if (descriptor == null || descriptor.getName().isSpecial()) return false
if (!checkTypeParameters && descriptor is TypeParameterDescriptor) return true
return scope != null && scope.getClassifier(descriptor.getName()) == descriptor
}
public fun JetType.approximateWithResolvableType(scope: JetScope?, checkTypeParameters: Boolean): JetType {
if (isError() || isResolvableInScope(scope, checkTypeParameters)) return this
return supertypes().firstOrNull { it.isResolvableInScope(scope, checkTypeParameters) }
?: KotlinBuiltIns.getInstance().getAnyType()
}