Initial support of descriptor loading at runtime
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
<orderEntry type="module" module-name="serialization" />
|
||||
<orderEntry type="module" module-name="serialization.jvm" />
|
||||
<orderEntry type="module" module-name="builtins-serializer" />
|
||||
<orderEntry type="module" module-name="descriptors.runtime" />
|
||||
<orderEntry type="module" module-name="js.frontend" />
|
||||
<orderEntry type="module" module-name="js.tests" />
|
||||
<orderEntry type="module" module-name="preloader" />
|
||||
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.jvm.runtime
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAllTo
|
||||
import org.jetbrains.kotlin.codegen.GeneratedClassLoader
|
||||
import org.jetbrains.kotlin.codegen.GenerationUtils
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.jvm.compiler.ExpectedLoadErrorsUtil
|
||||
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.reflect.RuntimeModuleData
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRendererBuilder
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.RedeclarationHandler
|
||||
import org.jetbrains.kotlin.resolve.scopes.WritableScope.LockLevel
|
||||
import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import org.jetbrains.kotlin.test.TestCaseWithTmpdir
|
||||
import org.jetbrains.kotlin.test.util.RecursiveDescriptorComparator
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.io.File
|
||||
|
||||
public abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() {
|
||||
class object {
|
||||
private val renderer = DescriptorRendererBuilder()
|
||||
.setWithDefinedIn(false)
|
||||
.setExcludedAnnotationClasses(listOf(
|
||||
ExpectedLoadErrorsUtil.ANNOTATION_CLASS_NAME,
|
||||
"kotlin.deprecated",
|
||||
"kotlin.data",
|
||||
"org.jetbrains.annotations.NotNull",
|
||||
"org.jetbrains.annotations.Nullable",
|
||||
"org.jetbrains.annotations.Mutable",
|
||||
"org.jetbrains.annotations.ReadOnly"
|
||||
).map { FqName(it) })
|
||||
.setOverrideRenderingPolicy(DescriptorRenderer.OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE)
|
||||
.setIncludeSynthesizedParameterNames(false)
|
||||
.setIncludePropertyConstant(false)
|
||||
.setVerbose(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
protected fun doTest(ktFileName: String) {
|
||||
val ktFile = File(ktFileName)
|
||||
|
||||
val environment = JetTestUtils.createEnvironmentWithMockJdkAndIdeaAnnotations(myTestRootDisposable, ConfigurationKind.ALL)
|
||||
val jetFile = JetTestUtils.createFile(ktFileName, FileUtil.loadFile(ktFile, true), environment.getProject())
|
||||
val classFileFactory = GenerationUtils.compileFileGetClassFileFactoryForTest(jetFile)
|
||||
val classLoader = GeneratedClassLoader(classFileFactory, null, ForTestCompileRuntime.runtimeJarForTests().toURI().toURL())
|
||||
|
||||
classFileFactory.writeAllTo(tmpdir)
|
||||
|
||||
val module = RuntimeModuleData.create(classLoader).module
|
||||
|
||||
// Since runtime package view descriptor doesn't support getAllDescriptors(), we construct a synthetic package view here.
|
||||
// It has in its scope descriptors for all the classes and top level members generated by the compiler
|
||||
val actual = object : PackageViewDescriptor {
|
||||
val scope = WritableScopeImpl(JetScope.Empty, this, RedeclarationHandler.THROW_EXCEPTION, "runtime descriptor loader test")
|
||||
|
||||
override fun getFqName() = LoadDescriptorUtil.TEST_PACKAGE_FQNAME
|
||||
override fun getMemberScope() = scope
|
||||
override fun getModule() = module
|
||||
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R =
|
||||
visitor.visitPackageViewDescriptor(this, data)
|
||||
|
||||
override fun getContainingDeclaration() = throw UnsupportedOperationException()
|
||||
override fun getOriginal() = throw UnsupportedOperationException()
|
||||
override fun substitute(substitutor: TypeSubstitutor) = throw UnsupportedOperationException()
|
||||
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) = throw UnsupportedOperationException()
|
||||
override fun getAnnotations() = throw UnsupportedOperationException()
|
||||
override fun getName() = throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
val scope = actual.getMemberScope()
|
||||
scope.changeLockLevel(LockLevel.BOTH)
|
||||
|
||||
for (outputFile in classLoader.getAllGeneratedFiles()) {
|
||||
val className = outputFile.relativePath.substringBeforeLast(".class").replace('/', '.').replace('\\', '.')
|
||||
|
||||
val klass = classLoader.loadClass(className).sure("Couldn't load class $className")
|
||||
|
||||
when (ReflectKotlinClass(klass).getClassHeader().kind) {
|
||||
KotlinClassHeader.Kind.PACKAGE_FACADE -> {
|
||||
val packageView = module.getPackage(actual.getFqName()) ?: error("Couldn't resolve package ${actual.getFqName()}")
|
||||
for (descriptor in packageView.getMemberScope().getAllDescriptors()) {
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> scope.addFunctionDescriptor(descriptor)
|
||||
is PropertyDescriptor -> scope.addPropertyDescriptor(descriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
KotlinClassHeader.Kind.CLASS -> {
|
||||
val classDescriptor =
|
||||
resolveClassByFqNameInModule(module, FqNameUnsafe(className)).sure("Couldn't resolve class $className")
|
||||
if (classDescriptor.getContainingDeclaration() is PackageFragmentDescriptor) {
|
||||
scope.addClassifierDescriptor(classDescriptor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val expected = LoadDescriptorUtil.loadTestPackageAndBindingContextFromJavaRoot(tmpdir, getTestRootDisposable(),
|
||||
ConfigurationKind.ALL)
|
||||
val configuration = RecursiveDescriptorComparator.DONT_INCLUDE_METHODS_OF_OBJECT
|
||||
.checkPrimaryConstructors(true)
|
||||
.checkPropertyAccessors(true)
|
||||
.withRenderer(renderer)
|
||||
RecursiveDescriptorComparator.validateAndCompareDescriptors(expected.first, actual, configuration, null)
|
||||
}
|
||||
|
||||
private fun resolveClassByFqNameInModule(module: ModuleDescriptor, fqName: FqNameUnsafe): ClassDescriptor? {
|
||||
if (fqName.isRoot()) return null
|
||||
|
||||
if (fqName.isSafe()) {
|
||||
val topLevel = module.resolveTopLevelClass(fqName.toSafe())
|
||||
if (topLevel != null) return topLevel
|
||||
}
|
||||
|
||||
val parent = resolveClassByFqNameInModule(module, fqName.parent()) ?: return null
|
||||
return parent.getUnsubstitutedInnerClassesScope().getClassifier(fqName.shortName()) as? ClassDescriptor
|
||||
}
|
||||
}
|
||||
+3060
File diff suppressed because it is too large
Load Diff
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.context.GlobalContext
|
||||
import org.jetbrains.kotlin.di.InjectorForTopDownAnalyzerForJvm
|
||||
import org.jetbrains.kotlin.jvm.compiler.LoadDescriptorUtil
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.resolve.TopDownAnalysisParameters
|
||||
import org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
|
||||
@@ -83,15 +80,6 @@ public abstract class AbstractLocalClassProtoTest : TestCaseWithTmpdir() {
|
||||
)
|
||||
}
|
||||
|
||||
private val Class<*>.classId: ClassId
|
||||
get() {
|
||||
if (getEnclosingMethod() != null || getEnclosingConstructor() != null) {
|
||||
return ClassId(FqName.ROOT, FqNameUnsafe(getName()), /* local = */ true)
|
||||
}
|
||||
return getDeclaringClass()?.classId?.createNestedClassId(Name.identifier(getSimpleName()))
|
||||
?: ClassId.topLevel(FqName(getName()))
|
||||
}
|
||||
|
||||
private fun assertHasAnnotationData(clazz: Class<*>) {
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
val annotation = clazz.getAnnotation(
|
||||
|
||||
Reference in New Issue
Block a user