Support type aliases in stub builder

This commit is contained in:
Denis Zharkov
2016-06-27 18:23:42 +03:00
parent daa356860c
commit e24f0653fb
14 changed files with 262 additions and 14 deletions
@@ -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(
@@ -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(
@@ -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 {
@@ -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) {
@@ -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
}
@@ -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]
@@ -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/");