Do not load error classes in ReflectionTypes

Previously ReflectionTypes.find returned an error class in case a class
is not found in the module dependencies. The problem with this approach
is that each call site should call ErrorUtils.isError on the result and
report an error if needed, in order to stop this type from reaching the
codegen, which can't handle error types.

Now we create a MockClassDescriptor instance instead. It's not an error
class, so it'll be handled correctly in the codegen. Also its scope is
empty and errors are reported on any non-trivial usage (see
MissingDependencyClassChecker), so this approach is not worse than error
classes

 #KT-16484 Fixed
This commit is contained in:
Alexander Udalov
2017-02-22 14:13:17 +03:00
parent 794cc1e3be
commit 12b48f86e7
9 changed files with 61 additions and 66 deletions
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.serialization.deserialization.NotFoundClasses
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -34,12 +35,16 @@ private val ANY_MEMBER_NAMES = setOf("equals", "hashCode", "toString")
/**
* Checks that there are no usages of reflection API which will fail at runtime.
*/
abstract class AbstractReflectionApiCallChecker(private val module: ModuleDescriptor, storageManager: StorageManager) : CallChecker {
abstract class AbstractReflectionApiCallChecker(
private val module: ModuleDescriptor,
private val notFoundClasses: NotFoundClasses,
storageManager: StorageManager
) : CallChecker {
protected abstract val isWholeReflectionApiAvailable: Boolean
protected abstract fun report(element: PsiElement, context: CallCheckerContext)
private val kPropertyClasses by storageManager.createLazyValue {
val reflectionTypes = ReflectionTypes(module)
val reflectionTypes = ReflectionTypes(module, notFoundClasses)
setOf(reflectionTypes.kProperty0, reflectionTypes.kProperty1, reflectionTypes.kProperty2)
}
@@ -120,9 +120,6 @@ class DoubleColonExpressionResolver(
val variance =
if (result is DoubleColonLHS.Expression && !result.isObjectQualifier) Variance.OUT_VARIANCE else Variance.INVARIANT
val kClassType = reflectionTypes.getKClassType(Annotations.EMPTY, type, variance)
if (kClassType.isError) {
c.trace.report(MISSING_DEPENDENCY_CLASS.on(expression.receiverExpression!!, KotlinBuiltIns.FQ_NAMES.kClass.toSafe()))
}
return dataFlowAnalyzer.checkType(createTypeInfo(kClassType, dataFlowInfo), expression, c)
}
}
@@ -535,9 +532,6 @@ class DoubleColonExpressionResolver(
checkReferenceIsToAllowedMember(descriptor, context.trace, expression)
val type = createKCallableTypeForReference(descriptor, lhs, reflectionTypes, context.scope.ownerDescriptor) ?: return null
if (type.isError) {
context.trace.report(MISSING_DEPENDENCY_CLASS.on(expression, KotlinBuiltIns.FQ_NAMES.kCallable.toSafe()))
}
when (descriptor) {
is FunctionDescriptor -> bindFunctionReference(expression, type, context)
@@ -580,13 +574,10 @@ class DoubleColonExpressionResolver(
/* isCoroutine = */ false
)
val parameterTypes = if (type.isError) emptyList() else type.arguments.dropLast(1)
val returnType = if (type.isError) null else type.arguments.last().type
functionDescriptor.initialize(
null, null, emptyList(),
createValueParametersForInvokeInFunctionType(functionDescriptor, parameterTypes),
returnType,
createValueParametersForInvokeInFunctionType(functionDescriptor, type.arguments.dropLast(1)),
type.arguments.last().type,
Modality.FINAL,
Visibilities.PUBLIC
)