diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt index b3a7dc16375..da967249005 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/constraintsCollector.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.nj2k.nullabilityAnalysis +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor @@ -12,26 +13,46 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall -import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi +import org.jetbrains.kotlin.nj2k.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.asAssignment import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType import org.jetbrains.kotlin.resolve.bindingContextUtil.getTargetFunction import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.components.isVararg -import org.jetbrains.kotlin.resolve.descriptorUtil.firstOverridden import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs + +internal class LabelToFunctionTypeVariableMapper(analysisContext: AnalysisContext) { + private val labelToFunction = analysisContext.declarationToTypeVariable.mapNotNull { (declaration, _) -> + if (declaration !is KtNamedFunction) return@mapNotNull null + val label = declaration.nameIdentifier?.getLabel() ?: return@mapNotNull null + label to declaration + }.toMap() + + fun functionByLabel(label: JKElementInfoLabel): KtNamedFunction? = + labelToFunction[label] + +} + internal class ConstraintsCollector( private val analysisContext: AnalysisContext, + private val converterContext: NewJ2kConverterContext, printConstraints: Boolean ) { private val boundTypeStorage = BoundTypeStorage(analysisContext, printConstraints) private val constraintBuilder = ConstraintBuilder(boundTypeStorage) + private val labelToFunctionTypeVariableMapper = LabelToFunctionTypeVariableMapper(analysisContext) + + private val PsiElement.elementInfo: List? + get() = getLabel()?.let { label -> + converterContext.elementsInfoStorage.getInfoForLabel(label) + } private inline val KtExpression.boundType get() = boundTypeStorage.boundTypeFor(this) @@ -161,47 +182,71 @@ internal class ConstraintsCollector( } - private fun collectSuperDeclarationConstraintsForFunction(function: KtNamedFunction) = with(constraintBuilder) { - val descriptor = function.resolveToDescriptorIfAny() ?: return - val superDeclarationDescriptor = descriptor.firstOverridden { true } - ?.takeIf { it != descriptor } - ?.safeAs() - ?: return - - val containingSuperClassBoundType = - superDeclarationDescriptor.containingDeclaration.safeAs()?.let { klass -> - GenericBoundType( - DescriptorClassReference(klass), - emptyList(),//TODO, - isNull = false - ) + private fun SuperFunctionInfo.superFunctionBoundType( + originalFunctionDescriptor: FunctionDescriptor + ): BoundType? = + when (this) { + is ExternalSuperFunctionInfo -> { + val containingSuperClassBoundType = + descriptor.containingDeclaration.safeAs()?.let { klass -> + GenericBoundType( + DescriptorClassReference(klass), + emptyList(),//TODO, + isNull = false + ) + } + originalFunctionDescriptor.returnType?.let { type -> + boundTypeStorage.boundTypeForType(type, containingSuperClassBoundType, emptyMap()/*TODO*/) + } } + is InternalSuperFunctionInfo -> { + labelToFunctionTypeVariableMapper.functionByLabel(label)?.let { function -> + analysisContext.declarationToTypeVariable[function]?.let { TypeVariableBoundType(it) } + } + } + } - val superFunctionPsi = superDeclarationDescriptor.findPsi() as? KtNamedFunction + private fun SuperFunctionInfo.superFunctionParameterBoundType(parameterIndex: Int): BoundType? { + return when (this) { + is ExternalSuperFunctionInfo -> { + val containingSuperClassBoundType = + descriptor.containingDeclaration.safeAs()?.let { klass -> + GenericBoundType( + DescriptorClassReference(klass), + emptyList(),//TODO, + isNull = false + ) + } + val parameter = descriptor.valueParameters.getOrNull(parameterIndex) ?: return null + boundTypeStorage.boundTypeForType(parameter.type, containingSuperClassBoundType, emptyMap()/*TODO*/) + } + is InternalSuperFunctionInfo -> { + val function = labelToFunctionTypeVariableMapper.functionByLabel(label) ?: return null + val parameter = function.valueParameters.getOrNull(parameterIndex) ?: return null + analysisContext.declarationToTypeVariable[parameter]?.let { TypeVariableBoundType(it) } + } + } + } - val superFunctionBoundType = - superFunctionPsi?.let { analysisContext.declarationToTypeVariable[it] }?.let { - TypeVariableBoundType(it) - } ?: descriptor.returnType?.let { type -> - boundTypeStorage.boundTypeForType(type, containingSuperClassBoundType, emptyMap()/*TODO*/) - } ?: return - analysisContext.declarationToTypeVariable[function]?.addEqualsNullabilityConstraint( - superFunctionBoundType, - ConstraintCameFrom.SUPER_DECLARATION - ) + private fun collectSuperDeclarationConstraintsForFunction(function: KtNamedFunction) = with(constraintBuilder) { + val (descriptor, superDeclarationDescriptors) = + function.nameIdentifier?.elementInfo?.firstIsInstanceOrNull() ?: return@with - for (parameterIndex in function.valueParameters.indices) { - val parameterTypeVariable = - function.valueParameters[parameterIndex].let { analysisContext.declarationToTypeVariable[it] } ?: return + for (superDeclarationInfo in superDeclarationDescriptors) { + val superFunctionBoundType = superDeclarationInfo.superFunctionBoundType(descriptor) ?: continue - val superParameterBoundType = superFunctionPsi?.valueParameters?.get(parameterIndex) - ?.let { analysisContext.declarationToTypeVariable[it] } - ?.let { TypeVariableBoundType(it) } - ?: superDeclarationDescriptor.valueParameters.getOrNull(parameterIndex) - ?.let { boundTypeStorage.boundTypeForType(it.type, containingSuperClassBoundType, emptyMap()/*TODO*/) } - ?: continue - parameterTypeVariable.addEqualsNullabilityConstraint(superParameterBoundType, ConstraintCameFrom.SUPER_DECLARATION) + analysisContext.declarationToTypeVariable[function]?.addEqualsNullabilityConstraint( + superFunctionBoundType, + ConstraintCameFrom.SUPER_DECLARATION + ) + + for (parameterIndex in function.valueParameters.indices) { + val parameterTypeVariable = + function.valueParameters[parameterIndex].let { analysisContext.declarationToTypeVariable[it] } ?: return + val superParameterBoundType = superDeclarationInfo.superFunctionParameterBoundType(parameterIndex) ?: return + parameterTypeVariable.addEqualsNullabilityConstraint(superParameterBoundType, ConstraintCameFrom.SUPER_DECLARATION) + } } } diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt index 1e319e55fe8..5ecac0cbf19 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/context.kt @@ -9,12 +9,18 @@ import com.intellij.openapi.editor.RangeMarker import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext +import org.jetbrains.kotlin.nj2k.JKElementInfoLabel +import org.jetbrains.kotlin.nj2k.asLabel import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType import org.jetbrains.kotlin.psi.psiUtil.elementsInRange import org.jetbrains.kotlin.utils.addToStdlib.safeAs -internal class ContextCreator(private val getNullability: (KtTypeElement) -> Nullability) { +internal class ContextCreator( + private val conversionContext: NewJ2kConverterContext, + private val getNullability: (KtTypeElement, NewJ2kConverterContext) -> Nullability +) { private fun KtCallableDeclaration.typeElement(): KtTypeElement? = typeReference?.typeElement @@ -62,7 +68,7 @@ internal class ContextCreator(private val getNullability: (KtTypeElement) -> Nul } private fun KtTypeElement.asTypeVariable(): TypeVariable { - val nullability = getNullability(this) + val nullability = getNullability(this, conversionContext) val classReference: ClassReference = classReference() val typeParameters: List = typeArgumentsAsTypes.mapIndexed { index, typeRef -> @@ -79,38 +85,40 @@ internal class ContextCreator(private val getNullability: (KtTypeElement) -> Nul } -fun nullabilityByUndefinedNullabilityComment(typeElement: KtTypeElement): Nullability { - val undefinedNullabilityComment = - typeElement.parent?.safeAs()?.getUndefinedNullabilityComment()?.also { it.delete() } +fun nullabilityByUndefinedNullabilityComment(typeElement: KtTypeElement, context: NewJ2kConverterContext): Nullability { + val hasUndefinedNullabilityLabel = + typeElement.parent?.safeAs()?.hasUndefinedNullabilityLabel(context) ?: false return when { - undefinedNullabilityComment != null -> Nullability.UNKNOWN + hasUndefinedNullabilityLabel -> Nullability.UNKNOWN typeElement is KtNullableType -> Nullability.NULLABLE else -> Nullability.NOT_NULL } } -private fun KtElement.getUndefinedNullabilityComment(): PsiComment? = - prevSibling?.safeAs()?.takeIf { it.text == UNDEFINED_NULLABILITY_COMMENT } - ?: parent?.safeAs()?.getUndefinedNullabilityComment() +fun PsiElement.getLabel(): JKElementInfoLabel? = + prevSibling?.safeAs()?.text?.asLabel() + ?: parent?.safeAs()?.getLabel() +private fun KtTypeReference.hasUndefinedNullabilityLabel(context: NewJ2kConverterContext) = + getLabel()?.let { label -> + context.elementsInfoStorage.getInfoForLabel(label).orEmpty().contains(org.jetbrains.kotlin.nj2k.UnknownNullability) + } ?: false -fun prepareTypeElementByMakingAllTypesNullableConsideringNullabilityComment(typeElement: KtTypeElement) { - val hasUndefinedNullabilityComment = - typeElement.parent?.safeAs()?.getUndefinedNullabilityComment() != null - if (hasUndefinedNullabilityComment) { +fun prepareTypeElementByMakingAllTypesNullableConsideringNullabilityComment(typeElement: KtTypeElement, context: NewJ2kConverterContext) { + val hasUndefinedNullabilityLabel = + typeElement.parent?.safeAs()?.hasUndefinedNullabilityLabel(context) ?: false + + if (hasUndefinedNullabilityLabel) { typeElement.changeNullability(toNullable = true) } } -fun preapareTypeElementByMakingAllTypesNullable(typeElement: KtTypeElement) { +fun prepareTypeElementByMakingAllTypesNullable(typeElement: KtTypeElement, conversionContext: NewJ2kConverterContext) { typeElement.changeNullability(toNullable = true) } -internal const val UNDEFINED_NULLABILITY_COMMENT = "/*UNDEFINED*/" - - internal data class AnalysisContext( val typeVariableOwners: List, val typeElementToTypeVariable: Map, diff --git a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt index 91ad895c99a..c87b48ac1b3 100644 --- a/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt +++ b/nj2k/nj2k-services/src/org/jetbrains/kotlin/nj2k/nullabilityAnalysis/nullabilityAnalysis.kt @@ -12,6 +12,8 @@ import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementVisitor import com.intellij.psi.util.parentOfType +import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext +import org.jetbrains.kotlin.nj2k.asLabel import org.jetbrains.kotlin.nj2k.postProcessing.resolve import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType @@ -73,22 +75,23 @@ internal fun KtTypeElement.classReference(): ClassReference { } class NullabilityAnalysisFacade( - private val getTypeElementNullability: (KtTypeElement) -> Nullability, - private val prepareTypeElement: (KtTypeElement) -> Unit, + private val conversionContext: NewJ2kConverterContext, + private val getTypeElementNullability: (KtTypeElement, NewJ2kConverterContext) -> Nullability, + private val prepareTypeElement: (KtTypeElement, NewJ2kConverterContext) -> Unit, private val debugPrint: Boolean ) { fun fixNullability(analysisScope: AnalysisScope) { CommandProcessor.getInstance().runUndoTransparentAction { runWriteAction { - analysisScope.prepareTypeElements(prepareTypeElement) - val context = ContextCreator(getTypeElementNullability).createContext(analysisScope) + analysisScope.prepareTypeElements(prepareTypeElement, conversionContext) + val context = ContextCreator(conversionContext, getTypeElementNullability).createContext(analysisScope) if (debugPrint) { with(Printer(context)) { analysisScope.forEach { it.addTypeVariablesNames() } } } - val constraints = ConstraintsCollector(context, debugPrint).collectConstraints(analysisScope) + val constraints = ConstraintsCollector(context, conversionContext, debugPrint).collectConstraints(analysisScope) Solver(context, debugPrint).solveConstraints(constraints) context.fixTypeVariablesNullability() analysisScope.clearUndefinedLabels() @@ -97,12 +100,15 @@ class NullabilityAnalysisFacade( } } -private fun AnalysisScope.prepareTypeElements(prepareTypeElement: (KtTypeElement) -> Unit) { +private fun AnalysisScope.prepareTypeElements( + prepareTypeElement: (KtTypeElement, NewJ2kConverterContext) -> Unit, + conversionContext: NewJ2kConverterContext +) { val typeElements = flatMap { it.collectDescendantsOfType() } typeElements.forEach { typeReference -> val typeElement = typeReference.typeElement ?: return@forEach if (typeElement.parentOfType() == null) { - prepareTypeElement(typeElement) + prepareTypeElement(typeElement, conversionContext) } } } @@ -117,7 +123,7 @@ private fun AnalysisScope.clearUndefinedLabels() { } override fun visitComment(comment: PsiComment) { - if (comment.text == UNDEFINED_NULLABILITY_COMMENT) { + if (comment.text.asLabel() != null) { comments += comment } } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt new file mode 100644 index 00000000000..0841da634f4 --- /dev/null +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/JKElementInfoStorage.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.nj2k + +import org.jetbrains.kotlin.descriptors.FunctionDescriptor + + +interface JKElementInfo + +sealed class SuperFunctionInfo +data class ExternalSuperFunctionInfo(val descriptor: FunctionDescriptor) : SuperFunctionInfo() +data class InternalSuperFunctionInfo(val label: JKElementInfoLabel) : SuperFunctionInfo() + +data class FunctionInfo(val originalDescriptor: FunctionDescriptor, val superFunctions: List) : JKElementInfo + +object UnknownNullability : JKElementInfo + +inline class JKElementInfoLabel(val label: String) { + inline fun render(): String = "/*@@$label@@*/" + + companion object { + val LABEL_REGEX = """/\*@@(\w+)@@\*/""".toRegex() + } +} + +fun String.asLabel(): JKElementInfoLabel? = + JKElementInfoLabel.LABEL_REGEX.matchEntire(this)?.groupValues?.getOrNull(1)?.let { JKElementInfoLabel(it) } + +class JKElementInfoStorage { + private val labelToInfo = mutableMapOf>() + private val elementToLabel = mutableMapOf() + + fun getOrCreateInfoForElement(element: Any): JKElementInfoLabel = + elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) } + + fun getOrCreateInfoForLabel(label: JKElementInfoLabel): List = + labelToInfo.getOrPut(label) { emptyList() } + + fun getInfoForLabel(label: JKElementInfoLabel): List? = + labelToInfo[label] + + + fun addEntry(element: Any, info: JKElementInfo) { + val label = elementToLabel.getOrPut(element) { JKElementInfoLabel(createRandomString()) } + labelToInfo[label] = labelToInfo[label].orEmpty() + info + elementToLabel[element] = label + } + + companion object { + private val charPool = ('a'..'z').toList() + private const val generatedStringLength = 6 + + private fun createRandomString(): String { + return (1..generatedStringLength) + .map { kotlin.random.Random.nextInt(0, charPool.size) } + .map(charPool::get) + .joinToString("") + } + } +} \ No newline at end of file diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt index ba839c9f1a7..90c58221b22 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/NewCodeBuilder.kt @@ -28,8 +28,8 @@ import org.jetbrains.kotlin.nj2k.tree.visitors.JKVisitorWithCommentsPrinting import org.jetbrains.kotlin.utils.Printer import org.jetbrains.kotlin.utils.addToStdlib.safeAs -class NewCodeBuilder { - +class NewCodeBuilder(context: NewJ2kConverterContext) { + private val elementInfoStorage = context.elementsInfoStorage val builder = StringBuilder() val printer = Printer(builder) @@ -399,6 +399,10 @@ class NewCodeBuilder { renderModifiersList(ktFunction) printer.printWithNoIndent(" fun ") ktFunction.typeParameterList.accept(this) + + elementInfoStorage.getOrCreateInfoForElement(ktFunction)?.also { + printer.printWithNoIndent(it.render()) + } ktFunction.name.accept(this) renderTokenElement(ktFunction.leftParen) renderList(ktFunction.parameters) { @@ -652,8 +656,8 @@ class NewCodeBuilder { private fun renderType(type: JKType, owner: JKTreeElement?) { if (type is JKNoTypeImpl) return - if (type.nullability == Nullability.Default) { - printer.print("/*UNDEFINED*/") + elementInfoStorage.getOrCreateInfoForElement(type)?.also { + printer.print(it.render()) } when (type) { is JKClassType -> { diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJ2kConverterContext.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJ2kConverterContext.kt index 7bbf727a830..7f6813ec62e 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJ2kConverterContext.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJ2kConverterContext.kt @@ -15,7 +15,7 @@ data class NewJ2kConverterContext( val converter: NewJavaToKotlinConverter, val inConversionContext: (PsiElement) -> Boolean, val importStorage: ImportStorage, - val elementsInfoStorage: ElementInfoStorage + val elementsInfoStorage: JKElementInfoStorage ) : ConverterContext { val project: Project get() = converter.project val typeFlavorCalculator = TypeFlavorCalculator(object : TypeFlavorConverterFacade { @@ -40,7 +40,7 @@ data class NewJ2kConverterContext( ), { false }, ImportStorage(), - ElementInfoStorage() + JKElementInfoStorage() ) } diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt index 5123d08edb5..a7ff6604087 100644 --- a/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/NewJavaToKotlinConverter.kt @@ -101,13 +101,14 @@ class NewJavaToKotlinConverter( symbolProvider, this, { it.containingFile in inputElements }, - importStorage + importStorage, + JKElementInfoStorage() ) ConversionsRunner.doApply(asts.mapNotNull { it.second }, context) val results = asts.map { (element, ast) -> if (ast == null) return@map null - val code = NewCodeBuilder().run { printCodeOut(ast) } + val code = NewCodeBuilder(context).run { printCodeOut(ast) } val parseContext = when (element) { is PsiStatement, is PsiExpression -> ParseContext.CODE_BLOCK else -> ParseContext.TOP_LEVEL diff --git a/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt new file mode 100644 index 00000000000..922e8986b81 --- /dev/null +++ b/nj2k/src/org/jetbrains/kotlin/nj2k/conversions/AddElementsInfoConversion.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.nj2k.conversions + +import com.intellij.psi.PsiMethod +import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMethodDescriptor +import org.jetbrains.kotlin.j2k.ast.Nullability +import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi +import org.jetbrains.kotlin.nj2k.* +import org.jetbrains.kotlin.nj2k.tree.* +import org.jetbrains.kotlin.nj2k.tree.impl.JKUniverseMethodSymbol +import org.jetbrains.kotlin.nj2k.tree.impl.psi + +class AddElementsInfoConversion(private val context: NewJ2kConverterContext) : RecursiveApplicableConversionBase() { + override fun applyToElement(element: JKTreeElement): JKTreeElement { + when (element) { + is JKTypeElement -> addInfoForTypeElement(element) + is JKKtFunction -> addInfoForFunction(element) + } + + return recurse(element) + } + + private fun addInfoForTypeElement(typeElement: JKTypeElement) { + typeElement.type.forAllInnerTypes { type -> + if (type.nullability == Nullability.Default) { + context.elementsInfoStorage.addEntry(type, UnknownNullability) + } + } + } + + private fun addInfoForFunction(function: JKKtFunction) { + val psiMethod = function.psi() ?: return + val descriptor = psiMethod.getJavaMethodDescriptor() ?: return + val superDescriptorsInfo = + descriptor.overriddenDescriptors.map { superDescriptor -> + val psi = superDescriptor.findPsi() ?: return@map ExternalSuperFunctionInfo(descriptor) + when (val symbol = context.symbolProvider.symbolsByPsi[psi]) { + is JKUniverseMethodSymbol -> + InternalSuperFunctionInfo( + context.elementsInfoStorage.getOrCreateInfoForElement(symbol.target) + ) + else -> ExternalSuperFunctionInfo(descriptor) + } + } + context.elementsInfoStorage.addEntry(function, FunctionInfo(descriptor, superDescriptorsInfo)) + } + + private fun JKType.forAllInnerTypes(action: (JKType) -> Unit) { + action(this) + if (this is JKParametrizedType) { + parameters.forEach { it.forAllInnerTypes(action) } + } + } +} \ No newline at end of file