Support type aliases in stub builder
This commit is contained in:
+2
-2
@@ -51,10 +51,10 @@ class KotlinBuiltInStubBuilder : ClsStubBuilder() {
|
||||
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
||||
|
||||
val fileStub = createFileStub(packageFqName)
|
||||
createCallableStubs(
|
||||
createDeclarationsStubs(
|
||||
fileStub, context,
|
||||
ProtoContainer.Package(packageFqName, context.nameResolver, context.typeTable, source = null),
|
||||
packageProto.functionList, packageProto.propertyList
|
||||
packageProto
|
||||
)
|
||||
for (classProto in file.classesToDecompile) {
|
||||
createClassStub(
|
||||
|
||||
+17
-2
@@ -31,12 +31,23 @@ import org.jetbrains.kotlin.serialization.ProtoBuf.MemberKind
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf.Modality
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
|
||||
fun createCallableStubs(
|
||||
fun createDeclarationsStubs(
|
||||
parentStub: StubElement<out PsiElement>,
|
||||
outerContext: ClsStubBuilderContext,
|
||||
protoContainer: ProtoContainer,
|
||||
packageProto: ProtoBuf.Package
|
||||
) {
|
||||
createDeclarationsStubs(
|
||||
parentStub, outerContext, protoContainer, packageProto.functionList, packageProto.propertyList, packageProto.typeAliasList)
|
||||
}
|
||||
|
||||
fun createDeclarationsStubs(
|
||||
parentStub: StubElement<out PsiElement>,
|
||||
outerContext: ClsStubBuilderContext,
|
||||
protoContainer: ProtoContainer,
|
||||
functionProtos: List<ProtoBuf.Function>,
|
||||
propertyProtos: List<ProtoBuf.Property>
|
||||
propertyProtos: List<ProtoBuf.Property>,
|
||||
typeAliasesProtos: List<ProtoBuf.TypeAlias>
|
||||
) {
|
||||
for (propertyProto in propertyProtos) {
|
||||
if (!shouldSkip(propertyProto.flags, outerContext.nameResolver.getName(propertyProto.name))) {
|
||||
@@ -48,6 +59,10 @@ fun createCallableStubs(
|
||||
FunctionClsStubBuilder(parentStub, outerContext, protoContainer, functionProto).build()
|
||||
}
|
||||
}
|
||||
|
||||
for (typeAliasProto in typeAliasesProtos) {
|
||||
createTypeAliasStub(parentStub, typeAliasProto, protoContainer, outerContext)
|
||||
}
|
||||
}
|
||||
|
||||
fun createConstructorStub(
|
||||
|
||||
+2
-1
@@ -226,7 +226,8 @@ private class ClassClsStubBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
createCallableStubs(classBody, c, thisAsProtoContainer, classProto.functionList, classProto.propertyList)
|
||||
createDeclarationsStubs(
|
||||
classBody, c, thisAsProtoContainer, classProto.functionList, classProto.propertyList, classProto.typeAliasList)
|
||||
}
|
||||
|
||||
private fun isClass(): Boolean {
|
||||
|
||||
+7
-2
@@ -44,6 +44,7 @@ import java.util.*
|
||||
class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
|
||||
|
||||
fun createTypeReferenceStub(parent: StubElement<out PsiElement>, type: Type) {
|
||||
if (type.hasAbbreviatedType()) return createTypeReferenceStub(parent, type.abbreviatedType)
|
||||
val typeReference = KotlinPlaceHolderStubImpl<KtTypeReference>(parent, KtStubElementTypes.TYPE_REFERENCE)
|
||||
|
||||
val annotations = c.components.annotationLoader.loadTypeAnnotations(type, c.nameResolver).filterNot {
|
||||
@@ -61,7 +62,7 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
|
||||
}
|
||||
|
||||
when {
|
||||
type.hasClassName() -> createClassReferenceTypeStub(effectiveParent, type, annotations)
|
||||
type.hasClassName() || type.hasTypeAliasName() -> createClassReferenceTypeStub(effectiveParent, type, annotations)
|
||||
type.hasTypeParameter() -> createTypeParameterStub(c.typeParameters[type.typeParameter])
|
||||
type.hasTypeParameterName() -> createTypeParameterStub(c.nameResolver.getName(type.typeParameterName))
|
||||
}
|
||||
@@ -77,7 +78,11 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
|
||||
}
|
||||
}
|
||||
|
||||
val classId = c.nameResolver.getClassId(type.className)
|
||||
assert(type.hasClassName() || type.hasTypeAliasName()) {
|
||||
"Class reference stub must have either class or type alias name"
|
||||
}
|
||||
|
||||
val classId = c.nameResolver.getClassId(if (type.hasClassName()) type.className else type.typeAliasName)
|
||||
val shouldBuildAsFunctionType = isNumberedFunctionClassFqName(classId.asSingleFqName().toUnsafe())
|
||||
&& type.argumentList.none { it.projection == Projection.STAR }
|
||||
if (shouldBuildAsFunctionType) {
|
||||
|
||||
+4
-6
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.flags.FlagsToModifiers
|
||||
import org.jetbrains.kotlin.idea.stubindex.KotlinFileStubForIde
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
@@ -37,7 +36,6 @@ import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
||||
@@ -62,8 +60,8 @@ fun createPackageFacadeStub(
|
||||
): KotlinFileStubImpl {
|
||||
val fileStub = KotlinFileStubForIde.forFile(packageFqName, packageFqName.isRoot)
|
||||
setupFileStub(fileStub, packageFqName)
|
||||
createCallableStubs(fileStub, c, ProtoContainer.Package(packageFqName, c.nameResolver, c.typeTable, source = null),
|
||||
packageProto.functionList, packageProto.propertyList)
|
||||
createDeclarationsStubs(
|
||||
fileStub, c, ProtoContainer.Package(packageFqName, c.nameResolver, c.typeTable, source = null), packageProto)
|
||||
return fileStub
|
||||
}
|
||||
|
||||
@@ -78,7 +76,7 @@ fun createFileFacadeStub(
|
||||
val container = ProtoContainer.Package(
|
||||
packageFqName, c.nameResolver, c.typeTable, JvmPackagePartSource(JvmClassName.byClassId(ClassId.topLevel(facadeFqName)), null)
|
||||
)
|
||||
createCallableStubs(fileStub, c, container, packageProto.functionList, packageProto.propertyList)
|
||||
createDeclarationsStubs(fileStub, c, container, packageProto)
|
||||
return fileStub
|
||||
}
|
||||
|
||||
@@ -98,7 +96,7 @@ fun createMultifileClassStub(
|
||||
val partContext = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
|
||||
val container = ProtoContainer.Package(packageFqName, partContext.nameResolver, partContext.typeTable,
|
||||
JvmPackagePartSource(partFile))
|
||||
createCallableStubs(fileStub, partContext, container, packageProto.functionList, packageProto.propertyList)
|
||||
createDeclarationsStubs(fileStub, partContext, container, packageProto)
|
||||
}
|
||||
return fileStub
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.decompiler.stubBuilder
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.stubs.StubElement
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.flags.VISIBILITY
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinTypeAliasStubImpl
|
||||
import org.jetbrains.kotlin.serialization.Flags
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
|
||||
fun createTypeAliasStub(
|
||||
parent: StubElement<out PsiElement>,
|
||||
typeAliasProto: ProtoBuf.TypeAlias,
|
||||
protoContainer: ProtoContainer,
|
||||
context: ClsStubBuilderContext
|
||||
) {
|
||||
val shortName = context.nameResolver.getName(typeAliasProto.name)
|
||||
|
||||
val classId = when (protoContainer) {
|
||||
is ProtoContainer.Class -> protoContainer.classId.createNestedClassId(shortName)
|
||||
is ProtoContainer.Package -> ClassId.topLevel(protoContainer.fqName.child(shortName))
|
||||
}
|
||||
|
||||
val typeAlias =
|
||||
KotlinTypeAliasStubImpl(
|
||||
parent, classId.shortClassName.ref(), classId.asSingleFqName().ref(),
|
||||
isTopLevel = !classId.isNestedClass)
|
||||
|
||||
createModifierListStubForDeclaration(typeAlias, typeAliasProto.flags, arrayListOf(VISIBILITY), listOf())
|
||||
|
||||
val typeStubBuilder = TypeClsStubBuilder(context)
|
||||
val restConstraints = typeStubBuilder.createTypeParameterListStub(typeAlias, typeAliasProto.typeParameterList)
|
||||
assert(restConstraints.isEmpty()) {
|
||||
"'where' constraints are not allowed for type aliases"
|
||||
}
|
||||
|
||||
if (Flags.HAS_ANNOTATIONS.get(typeAliasProto.flags)) {
|
||||
// TODO: support annotations
|
||||
// createAnnotationStubs(context.components.annotationLoader.loadClassAnnotations(thisAsProtoContainer), modifierList)
|
||||
}
|
||||
|
||||
typeStubBuilder.createTypeReferenceStub(typeAlias, typeAliasProto.underlyingType)
|
||||
}
|
||||
@@ -7,4 +7,6 @@ public final class TypeAliases public constructor() {
|
||||
public final fun foo(a: dependency.A /* = () -> kotlin.Unit */, b: test.TypeAliases.B /* = (dependency.A /* = () -> kotlin.Unit */) -> kotlin.Unit */, ta: test.Outer<kotlin.String, kotlin.Double>.Inner<kotlin.Int>.TA<kotlin.Boolean> /* = kotlin.collections.Map<kotlin.collections.Map<kotlin.String, out kotlin.Double>, kotlin.collections.Map<kotlin.Int, out kotlin.Boolean>> */): kotlin.Unit { /* compiled code */ }
|
||||
|
||||
public typealias B = (dependency.A) -> kotlin.Unit
|
||||
|
||||
private typealias Parametrized<E, F> = kotlin.collections.Map<E, F>
|
||||
}
|
||||
|
||||
@@ -8,10 +8,16 @@ class Outer<E, F> {
|
||||
}
|
||||
}
|
||||
|
||||
annotation class Ann
|
||||
class TypeAliases {
|
||||
|
||||
typealias B = (A) -> Unit
|
||||
|
||||
fun foo(a: A, b: B, ta: Outer<String, Double>.Inner<Int>.TA<Boolean>) {
|
||||
b.invoke(a)
|
||||
}
|
||||
|
||||
// TODO: annotations are unsupported yet
|
||||
@Ann
|
||||
private typealias Parametrized<E, F> = Map<E, F>
|
||||
}
|
||||
|
||||
@@ -24,4 +24,6 @@ private fun probablyNothing(): Nothing = throw IllegalStateException()
|
||||
|
||||
private val certainlyNothing: kotlin.Nothing = throw IllegalStateException()
|
||||
|
||||
class Nothing
|
||||
private typealias Alias<E> = (E) -> E
|
||||
|
||||
class Nothing
|
||||
|
||||
@@ -117,3 +117,17 @@ PsiJetFileStubImpl[package=foo.TopLevelMembers]
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=Int]
|
||||
TYPEALIAS:[fqName=foo.TopLevelMembers.Alias, isTopLevel=true, name=Alias]
|
||||
MODIFIER_LIST:[private]
|
||||
TYPE_PARAMETER_LIST:
|
||||
TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=E]
|
||||
TYPE_REFERENCE:
|
||||
FUNCTION_TYPE:
|
||||
VALUE_PARAMETER_LIST:
|
||||
VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=null]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=E]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=E]
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package dependency
|
||||
|
||||
typealias A = () -> Unit
|
||||
|
||||
fun foo(a: A) {
|
||||
a.invoke()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package test
|
||||
|
||||
import dependency.*
|
||||
|
||||
class Outer<E, F> {
|
||||
inner class Inner<G> {
|
||||
typealias TA<H> = Map<Map<E, F>, Map<G, H>>
|
||||
}
|
||||
}
|
||||
|
||||
annotation class Ann
|
||||
class TypeAliases {
|
||||
|
||||
typealias B = (A) -> Unit
|
||||
|
||||
fun foo(a: A, b: B, ta: Outer<String, Double>.Inner<Int>.TA<Boolean>) {
|
||||
b.invoke(a)
|
||||
}
|
||||
|
||||
// TODO: annotations are unsupported yet
|
||||
@Ann
|
||||
private typealias Parametrized<E, F> = Map<E, F>
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
PsiJetFileStubImpl[package=test]
|
||||
PACKAGE_DIRECTIVE:
|
||||
REFERENCE_EXPRESSION:[referencedName=test]
|
||||
IMPORT_LIST:
|
||||
CLASS:[fqName=test.TypeAliases, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=true, name=TypeAliases, superNames=[]]
|
||||
MODIFIER_LIST:[public final]
|
||||
PRIMARY_CONSTRUCTOR:
|
||||
MODIFIER_LIST:[public]
|
||||
VALUE_PARAMETER_LIST:
|
||||
CLASS_BODY:
|
||||
FUN:[fqName=test.TypeAliases.foo, hasBlockBody=true, hasBody=true, hasTypeParameterListBeforeFunctionName=false, isExtension=false, isTopLevel=false, name=foo]
|
||||
MODIFIER_LIST:[public final]
|
||||
VALUE_PARAMETER_LIST:
|
||||
VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=a]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=dependency]
|
||||
REFERENCE_EXPRESSION:[referencedName=A]
|
||||
VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=b]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=test]
|
||||
REFERENCE_EXPRESSION:[referencedName=TypeAliases]
|
||||
REFERENCE_EXPRESSION:[referencedName=B]
|
||||
VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=ta]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=test]
|
||||
REFERENCE_EXPRESSION:[referencedName=Outer]
|
||||
TYPE_ARGUMENT_LIST:
|
||||
TYPE_PROJECTION:[projectionKind=NONE]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=String]
|
||||
TYPE_PROJECTION:[projectionKind=NONE]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=Double]
|
||||
REFERENCE_EXPRESSION:[referencedName=Inner]
|
||||
TYPE_ARGUMENT_LIST:
|
||||
TYPE_PROJECTION:[projectionKind=NONE]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=Int]
|
||||
REFERENCE_EXPRESSION:[referencedName=TA]
|
||||
TYPE_ARGUMENT_LIST:
|
||||
TYPE_PROJECTION:[projectionKind=NONE]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=Boolean]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=Unit]
|
||||
TYPEALIAS:[fqName=test.TypeAliases.B, isTopLevel=false, name=B]
|
||||
MODIFIER_LIST:[public]
|
||||
TYPE_REFERENCE:
|
||||
FUNCTION_TYPE:
|
||||
VALUE_PARAMETER_LIST:
|
||||
VALUE_PARAMETER:[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=null]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=dependency]
|
||||
REFERENCE_EXPRESSION:[referencedName=A]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=Unit]
|
||||
TYPEALIAS:[fqName=test.TypeAliases.Parametrized, isTopLevel=false, name=Parametrized]
|
||||
MODIFIER_LIST:[private]
|
||||
TYPE_PARAMETER_LIST:
|
||||
TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=E]
|
||||
TYPE_PARAMETER:[fqName=null, isInVariance=false, isOutVariance=false, name=F]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=kotlin]
|
||||
REFERENCE_EXPRESSION:[referencedName=collections]
|
||||
REFERENCE_EXPRESSION:[referencedName=Map]
|
||||
TYPE_ARGUMENT_LIST:
|
||||
TYPE_PROJECTION:[projectionKind=NONE]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=E]
|
||||
TYPE_PROJECTION:[projectionKind=NONE]
|
||||
TYPE_REFERENCE:
|
||||
USER_TYPE:
|
||||
REFERENCE_EXPRESSION:[referencedName=F]
|
||||
+6
@@ -179,6 +179,12 @@ public class ClsStubBuilderTestGenerated extends AbstractClsStubBuilderTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeAliases")
|
||||
public void testTypeAliases() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/stubBuilder/TypeAliases/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("TypeBoundsAndDelegationSpecifiers")
|
||||
public void testTypeBoundsAndDelegationSpecifiers() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/stubBuilder/TypeBoundsAndDelegationSpecifiers/");
|
||||
|
||||
Reference in New Issue
Block a user