Fixes and refactorings after review
This commit is contained in:
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.ScriptEnvironmentPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
@@ -631,9 +631,9 @@ public class PropertyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ScriptEnvPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
|
||||
public static final String MAP_IFACE_NAME = "java/util/Map";
|
||||
public static final String MAP_FIELD_NAME = "environment";
|
||||
static class ScriptEnvPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
|
||||
public static final Type MAP_IFACE_TYPE = Type.getObjectType("java/util/Map");
|
||||
public static final String MAP_FIELD_NAME = "$scriptEnvironment";
|
||||
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
|
||||
|
||||
public ScriptEnvPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
|
||||
@@ -645,20 +645,20 @@ public class PropertyCodegen {
|
||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||
InstructionAdapter v = codegen.v;
|
||||
|
||||
String intScriptName =
|
||||
state.getTypeMapper().mapClass((ClassifierDescriptor)(propertyAccessorDescriptor.getCorrespondingProperty().getContainingDeclaration())).getClassName();
|
||||
v.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
v.visitFieldInsn(Opcodes.GETFIELD, intScriptName, MAP_FIELD_NAME, Type.getObjectType(MAP_IFACE_NAME).getDescriptor());
|
||||
v.visitLdcInsn(propertyAccessorDescriptor.getCorrespondingProperty().getName().asString());
|
||||
Type scriptType = state.getTypeMapper().mapOwner(propertyAccessorDescriptor);
|
||||
String scriptInternalName = scriptType.getInternalName();
|
||||
v.load(0, scriptType);
|
||||
v.getfield(scriptInternalName, MAP_FIELD_NAME, MAP_IFACE_TYPE.getDescriptor());
|
||||
v.aconst(propertyAccessorDescriptor.getCorrespondingProperty().getName().asString());
|
||||
if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) {
|
||||
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_NAME, "get",
|
||||
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true);
|
||||
v.invokeinterface(MAP_IFACE_TYPE.getInternalName(), "get",
|
||||
Type.getMethodDescriptor(AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE));
|
||||
}
|
||||
else {
|
||||
Type valueType = state.getTypeMapper().mapType(propertyAccessorDescriptor.getCorrespondingProperty());
|
||||
v.load(1, valueType);
|
||||
StackValue.coerce(valueType, AsmTypes.OBJECT_TYPE, v);
|
||||
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_NAME, "set",
|
||||
v.visitMethodInsn(Opcodes.INVOKEINTERFACE, MAP_IFACE_TYPE.getInternalName(), "put",
|
||||
Type.getMethodDescriptor(Type.BOOLEAN_TYPE, AsmTypes.OBJECT_TYPE, AsmTypes.OBJECT_TYPE), true);
|
||||
}
|
||||
Type returnType = state.getTypeMapper().mapReturnType(propertyAccessorDescriptor);
|
||||
|
||||
@@ -168,10 +168,10 @@ class ScriptCodegen private constructor(
|
||||
|
||||
if (scriptDefinition.environmentVariables.isNotEmpty()) {
|
||||
val envParamIndex = frameMap.enterTemp(AsmTypes.OBJECT_TYPE)
|
||||
val mapType = Type.getObjectType("java/util/Map")
|
||||
val mapType = PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_IFACE_TYPE
|
||||
iv.load(0, classType)
|
||||
iv.load(envParamIndex, mapType)
|
||||
iv.putfield(classType.internalName, "environment", mapType.descriptor)
|
||||
iv.putfield(classType.internalName, PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_FIELD_NAME, mapType.descriptor)
|
||||
}
|
||||
|
||||
val codegen = ExpressionCodegen(mv, frameMap, Type.VOID_TYPE, methodContext, state, this)
|
||||
@@ -210,8 +210,8 @@ class ScriptCodegen private constructor(
|
||||
classBuilder.newField(
|
||||
NO_ORIGIN,
|
||||
ACC_PUBLIC or ACC_FINAL,
|
||||
"environment",
|
||||
Type.getObjectType("java/util/Map").descriptor,
|
||||
PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_FIELD_NAME,
|
||||
PropertyCodegen.ScriptEnvPropertyAccessorStrategy.MAP_IFACE_TYPE.descriptor,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.ScriptEnvironmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentDescriptor
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@@ -412,7 +412,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
setCompatibleBuild()
|
||||
// If not disabled explicitly, we should always support at least the standard script definition
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
!configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).contains(StandardScriptDefinition)
|
||||
StandardScriptDefinition !in configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
|
||||
@@ -205,9 +205,6 @@ class KotlinCoreEnvironment private constructor(
|
||||
})
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
// We should always support at least the standard script definition
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
scriptDefinitionProvider.setScriptDefinitionsSources(
|
||||
@@ -411,6 +408,11 @@ class KotlinCoreEnvironment private constructor(
|
||||
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
|
||||
): KotlinCoreEnvironment {
|
||||
setCompatibleBuild()
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
StandardScriptDefinition !in configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
val appEnv = getOrCreateApplicationEnvironmentForProduction(configuration)
|
||||
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
|
||||
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
|
||||
@@ -445,7 +447,10 @@ class KotlinCoreEnvironment private constructor(
|
||||
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
|
||||
): KotlinCoreEnvironment {
|
||||
val configuration = initialConfiguration.copy()
|
||||
if (configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()) {
|
||||
// in tests we assume that standard definition should only be added if no other explicit defs are already added
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
// Tests are supposed to create a single project and dispose it right after use
|
||||
|
||||
@@ -207,9 +207,6 @@ class KotlinCoreEnvironment private constructor(
|
||||
})
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
// We should always support at least the standard script definition
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
scriptDefinitionProvider.setScriptDefinitionsSources(
|
||||
@@ -413,6 +410,11 @@ class KotlinCoreEnvironment private constructor(
|
||||
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
|
||||
): KotlinCoreEnvironment {
|
||||
setCompatibleBuild()
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
StandardScriptDefinition !in configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS)
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
val appEnv = getOrCreateApplicationEnvironmentForProduction(configuration)
|
||||
// Disposing of the environment is unsafe in production then parallel builds are enabled, but turning it off universally
|
||||
// breaks a lot of tests, therefore it is disabled for production and enabled for tests
|
||||
@@ -447,7 +449,10 @@ class KotlinCoreEnvironment private constructor(
|
||||
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
|
||||
): KotlinCoreEnvironment {
|
||||
val configuration = initialConfiguration.copy()
|
||||
if (configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()) {
|
||||
// in tests we assume that standard definition should only be added if no other explicit defs are already added
|
||||
if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) &&
|
||||
configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS).isEmpty()
|
||||
) {
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition)
|
||||
}
|
||||
// Tests are supposed to create a single project and dispose it right after use
|
||||
|
||||
@@ -98,8 +98,8 @@ public interface Errors {
|
||||
DiagnosticFactory2<PsiElement, String, String> API_NOT_AVAILABLE = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, FqName> MISSING_DEPENDENCY_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, FqName> MISSING_SCRIPT_RECEIVER_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, FqName> MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_RECEIVER_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> PRE_RELEASE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, IncompatibleVersionErrorData<?>> INCOMPATIBLE_CLASS = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
|
||||
+5
-116
@@ -18,11 +18,8 @@ package org.jetbrains.kotlin.resolve.lazy.descriptors
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -33,16 +30,14 @@ import org.jetbrains.kotlin.resolve.lazy.LazyClassContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.kotlin.resolve.lazy.data.KtScriptInfo
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.ClassMemberDeclarationProvider
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.script.ScriptEnvironmentDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.*
|
||||
import org.jetbrains.kotlin.resolve.source.toSourceElement
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptHelper
|
||||
import org.jetbrains.kotlin.script.ScriptPriorities
|
||||
import org.jetbrains.kotlin.script.getScriptDefinition
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KType
|
||||
@@ -102,8 +97,8 @@ class LazyScriptDescriptor(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun findTypeDescriptor(type: KType, errorDiagnostic: DiagnosticFactory1<PsiElement, FqName>): ClassDescriptor? {
|
||||
val receiverClassId = type.classifier?.let { it as? KClass<*> }?.classId
|
||||
internal fun findTypeDescriptor(type: KType, errorDiagnostic: DiagnosticFactory1<PsiElement, String>): ClassDescriptor? {
|
||||
val receiverClassId = type.classId
|
||||
return receiverClassId?.let {
|
||||
module.findClassAcrossModuleDependencies(it)
|
||||
} ?: also {
|
||||
@@ -111,7 +106,7 @@ class LazyScriptDescriptor(
|
||||
resolveSession.trace.report(
|
||||
errorDiagnostic.on(
|
||||
scriptInfo.script,
|
||||
receiverClassId?.asSingleFqName() ?: FqName(type.toString())
|
||||
receiverClassId?.asSingleFqName()?.toString() ?: type.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -123,7 +118,7 @@ class LazyScriptDescriptor(
|
||||
ScriptEnvironmentDescriptor(this)
|
||||
}
|
||||
|
||||
override fun getScriptEnvironmentProperties(): List<PropertyDescriptor> = scriptEnvironment().properties
|
||||
override fun getScriptEnvironmentProperties(): List<PropertyDescriptor> = scriptEnvironment().properties()
|
||||
|
||||
private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue {
|
||||
var outerScope = super.getOuterScope()
|
||||
@@ -156,109 +151,3 @@ private val KClass<*>.classId: ClassId
|
||||
private val KType.classId: ClassId?
|
||||
get() = classifier?.let { it as? KClass<*> }?.classId
|
||||
|
||||
class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
|
||||
MutableClassDescriptor(
|
||||
script, ClassKind.CLASS, false, false,
|
||||
Name.special("<synthetic script environment for ${script.name}>"), SourceElement.NO_SOURCE, LockBasedStorageManager.NO_LOCKS
|
||||
) {
|
||||
|
||||
init {
|
||||
modality = Modality.FINAL
|
||||
visibility = Visibilities.PUBLIC
|
||||
setTypeParameterDescriptors(emptyList())
|
||||
createTypeConstructor()
|
||||
}
|
||||
|
||||
private val memberScope by lazy {
|
||||
ScriptEnvironmentMemberScope(
|
||||
script.name.identifier,
|
||||
properties
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUnsubstitutedMemberScope(): MemberScope = memberScope
|
||||
|
||||
val properties by lazy {
|
||||
script.scriptDefinition.environmentVariables.mapNotNull { (name, type) ->
|
||||
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
|
||||
name to it
|
||||
}
|
||||
}.map { (key, value) ->
|
||||
ScriptEnvironmentPropertyDescriptor(
|
||||
Name.identifier(key),
|
||||
value,
|
||||
thisAsReceiverParameter,
|
||||
true,
|
||||
script
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ScriptEnvironmentMemberScope(
|
||||
private val scriptId: String,
|
||||
private val environmentProperties: List<PropertyDescriptor>
|
||||
) : MemberScopeImpl() {
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> =
|
||||
environmentProperties.filter { kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK) && nameFilter(it.name) }
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
|
||||
environmentProperties.filter { it.name == name }
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println("Scope of script environment: $scriptId")
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptEnvironmentPropertyDescriptor(
|
||||
name: Name,
|
||||
typeDescriptor: ClassDescriptor,
|
||||
receiver: ReceiverParameterDescriptor?,
|
||||
isVar: Boolean,
|
||||
script: LazyScriptDescriptor
|
||||
) : PropertyDescriptorImpl(
|
||||
script,
|
||||
null,
|
||||
Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
|
||||
isVar,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE,
|
||||
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
|
||||
/* isDelegated = */ true
|
||||
) {
|
||||
init {
|
||||
setType(typeDescriptor.defaultType, emptyList<TypeParameterDescriptorImpl>(), receiver, null as KotlinType?)
|
||||
initialize(
|
||||
makePropertyGetterDescriptor(),
|
||||
if (!isVar) null else makePropertySetterDescriptor()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() =
|
||||
PropertyGetterDescriptorImpl(
|
||||
this, Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
|
||||
/* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE
|
||||
).also {
|
||||
it.initialize(returnType)
|
||||
}
|
||||
|
||||
private fun PropertyDescriptorImpl.makePropertySetterDescriptor() =
|
||||
PropertySetterDescriptorImpl(
|
||||
this, Annotations.EMPTY, Modality.OPEN, Visibilities.PUBLIC,
|
||||
/* isDefault = */ false, /* isExternal = */ false, /* isInline = */ false,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED, null, SourceElement.NO_SOURCE
|
||||
).also {
|
||||
it.initialize(
|
||||
ValueParameterDescriptorImpl(
|
||||
this, null, 0, Annotations.EMPTY, Name.special("<set-?>"), returnType,
|
||||
/* declaresDefaultValue = */ false, /* isCrossinline = */ false, /* isNoinline = */ false,
|
||||
null, SourceElement.NO_SOURCE
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.resolve.lazy.descriptors.script
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.MutableClassDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class ScriptEnvironmentDescriptor(script: LazyScriptDescriptor) :
|
||||
MutableClassDescriptor(
|
||||
script,
|
||||
ClassKind.CLASS, false, false,
|
||||
Name.special("<synthetic script environment for ${script.name}>"),
|
||||
SourceElement.NO_SOURCE,
|
||||
LockBasedStorageManager.NO_LOCKS
|
||||
) {
|
||||
|
||||
init {
|
||||
modality = Modality.FINAL
|
||||
visibility = Visibilities.PUBLIC
|
||||
setTypeParameterDescriptors(emptyList())
|
||||
createTypeConstructor()
|
||||
}
|
||||
|
||||
private val memberScope: () -> ScriptEnvironmentMemberScope = script.resolveSession.storageManager.createLazyValue {
|
||||
ScriptEnvironmentMemberScope(
|
||||
script.name.identifier,
|
||||
properties()
|
||||
)
|
||||
}
|
||||
|
||||
override fun getUnsubstitutedMemberScope(): MemberScope = memberScope()
|
||||
|
||||
val properties: () -> List<ScriptEnvironmentPropertyDescriptor> = script.resolveSession.storageManager.createLazyValue {
|
||||
script.scriptDefinition.environmentVariables.mapNotNull { (name, type) ->
|
||||
script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_ENVIRONMENT_PROPERTY_CLASS)?.let {
|
||||
name to it
|
||||
}
|
||||
}.map { (name, classDescriptor) ->
|
||||
ScriptEnvironmentPropertyDescriptor(
|
||||
Name.identifier(name),
|
||||
classDescriptor,
|
||||
thisAsReceiverParameter,
|
||||
true,
|
||||
script
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class ScriptEnvironmentMemberScope(
|
||||
private val scriptId: String,
|
||||
private val environmentProperties: List<PropertyDescriptor>
|
||||
) : MemberScopeImpl() {
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean
|
||||
): Collection<DeclarationDescriptor> =
|
||||
environmentProperties
|
||||
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> =
|
||||
environmentProperties.filter { it.name == name }
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println("Scope of script environment: $scriptId")
|
||||
}
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.resolve.lazy.descriptors.script
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class ScriptEnvironmentPropertyDescriptor(
|
||||
name: Name,
|
||||
typeDescriptor: ClassDescriptor,
|
||||
receiver: ReceiverParameterDescriptor?,
|
||||
isVar: Boolean,
|
||||
script: LazyScriptDescriptor
|
||||
) : PropertyDescriptorImpl(
|
||||
script,
|
||||
null,
|
||||
Annotations.EMPTY,
|
||||
Modality.OPEN,
|
||||
Visibilities.PUBLIC,
|
||||
isVar,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
SourceElement.NO_SOURCE,
|
||||
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
|
||||
/* isDelegated = */ false
|
||||
) {
|
||||
init {
|
||||
setType(typeDescriptor.defaultType, emptyList<TypeParameterDescriptorImpl>(), receiver, null as KotlinType?)
|
||||
initialize(
|
||||
makePropertyGetterDescriptor(),
|
||||
if (!isVar) null else makePropertySetterDescriptor()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PropertyDescriptorImpl.makePropertyGetterDescriptor() =
|
||||
PropertyGetterDescriptorImpl(
|
||||
this,
|
||||
Annotations.EMPTY,
|
||||
this.modality,
|
||||
this.visibility,
|
||||
/* isDefault = */
|
||||
false, /* isExternal = */
|
||||
false, /* isInline = */
|
||||
false,
|
||||
this.kind,
|
||||
null,
|
||||
SourceElement.NO_SOURCE
|
||||
).also {
|
||||
it.initialize(returnType)
|
||||
}
|
||||
|
||||
private fun PropertyDescriptorImpl.makePropertySetterDescriptor() =
|
||||
PropertySetterDescriptorImpl(
|
||||
this,
|
||||
Annotations.EMPTY,
|
||||
this.modality,
|
||||
this.visibility,
|
||||
/* isDefault = */
|
||||
false, /* isExternal = */
|
||||
false, /* isInline = */
|
||||
false,
|
||||
this.kind,
|
||||
null,
|
||||
SourceElement.NO_SOURCE
|
||||
).also {
|
||||
it.initialize(
|
||||
ValueParameterDescriptorImpl(
|
||||
this,
|
||||
null,
|
||||
0,
|
||||
Annotations.EMPTY,
|
||||
Name.special("<set-?>"),
|
||||
returnType,
|
||||
/* declaresDefaultValue = */
|
||||
false, /* isCrossinline = */
|
||||
false, /* isNoinline = */
|
||||
false,
|
||||
null,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.script
|
||||
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
@@ -34,7 +36,10 @@ interface ScriptDefinitionProvider {
|
||||
}
|
||||
}
|
||||
|
||||
fun ScriptDefinitionProvider.findScriptDefinition(file: VirtualFile): KotlinScriptDefinition? = findScriptDefinition(file.name)
|
||||
fun ScriptDefinitionProvider.findScriptDefinition(file: VirtualFile): KotlinScriptDefinition? {
|
||||
assert(!file.isDirectory) { "Do not expect directory in findScriptDefinition call: $file" }
|
||||
return findScriptDefinition(file.name)
|
||||
}
|
||||
|
||||
fun getScriptDefinition(file: VirtualFile, project: Project): KotlinScriptDefinition? =
|
||||
ScriptDefinitionProvider.getInstance(project).findScriptDefinition(file)
|
||||
@@ -51,10 +56,9 @@ abstract class LazyScriptDefinitionProvider : ScriptDefinitionProvider {
|
||||
private var _cachedDefinitions: Sequence<KotlinScriptDefinition>? = null
|
||||
private val cachedDefinitions: Sequence<KotlinScriptDefinition>
|
||||
get() {
|
||||
// assuming it is always called under read lock
|
||||
assert(lock.readLockCount > 0)
|
||||
assert(lock.readLockCount > 0) { "cachedDefinitions should only be used under the read lock" }
|
||||
if (_cachedDefinitions == null) lock.write {
|
||||
_cachedDefinitions = CashingSequence(currentDefinitions.constrainOnce())
|
||||
_cachedDefinitions = CachingSequence(currentDefinitions.constrainOnce())
|
||||
}
|
||||
return _cachedDefinitions!!
|
||||
}
|
||||
@@ -75,38 +79,31 @@ abstract class LazyScriptDefinitionProvider : ScriptDefinitionProvider {
|
||||
cachedDefinitions.firstOrNull { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
override fun isScript(fileName: String) =
|
||||
if (nonScriptFileName(fileName)) false
|
||||
else lock.read {
|
||||
cachedDefinitions.any { it.isScript(fileName) }
|
||||
}
|
||||
override fun isScript(fileName: String) = findScriptDefinition(fileName) != null
|
||||
|
||||
companion object {
|
||||
// TODO: find a common place for storing kotlin-related extensions and reuse values from it everywhere
|
||||
protected val nonScriptFilenameSuffixes = arrayOf(".kt", ".java")
|
||||
protected val nonScriptFilenameSuffixes = arrayOf(".${KotlinFileType.EXTENSION}", ".${JavaFileType.DEFAULT_EXTENSION}")
|
||||
}
|
||||
}
|
||||
|
||||
private class CashingSequence<T>(from: Sequence<T>) : Sequence<T> {
|
||||
private class CachingSequence<T>(from: Sequence<T>) : Sequence<T> {
|
||||
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private val sequenceIterator = from.iterator()
|
||||
private val cache = arrayListOf<T>()
|
||||
|
||||
private inner class CashingIterator : Iterator<T> {
|
||||
private inner class CachingIterator : Iterator<T> {
|
||||
|
||||
private val cacheIterator: Iterator<T> = cache.iterator()
|
||||
private var cacheRunOut = !cacheIterator.hasNext()
|
||||
private var cacheCursor = 0
|
||||
|
||||
private fun cacheHasNext() = !cacheRunOut && (cacheIterator.hasNext().also { if (!it) cacheRunOut = true })
|
||||
override fun hasNext(): Boolean = lock.read { cacheCursor < cache.size || sequenceIterator.hasNext() }
|
||||
|
||||
override fun hasNext(): Boolean = lock.read { cacheHasNext() || sequenceIterator.hasNext() }
|
||||
|
||||
override fun next(): T = lock.read {
|
||||
if (cacheHasNext()) cacheIterator.next()
|
||||
else sequenceIterator.next().also { lock.write { cache.add(it) } }
|
||||
override fun next(): T = lock.write {
|
||||
if (cacheCursor < cache.size) cache[cacheCursor++]
|
||||
else sequenceIterator.next().also { cache.add(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<T> = CashingIterator()
|
||||
override fun iterator(): Iterator<T> = CachingIterator()
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit
|
||||
}
|
||||
|
||||
private fun updateDefinitions() {
|
||||
assert(lock.isWriteLocked) { "updateDefinitions should only be called under the write lock" }
|
||||
definitions = definitionsByContributor.values.flattenTo(mutableListOf()).asSequence()
|
||||
clearCache()
|
||||
// TODO: clear by script type/definition
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package kotlin.script.experimental.basic
|
||||
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
import kotlin.reflect.full.createInstance
|
||||
import kotlin.script.experimental.annotations.KotlinScriptDefaultCompilationConfiguration
|
||||
import kotlin.script.experimental.api.*
|
||||
import kotlin.script.experimental.util.TypedKey
|
||||
@@ -18,15 +18,15 @@ open class AnnotationsBasedCompilationConfigurator(val environment: ScriptingEnv
|
||||
|
||||
override val defaultConfiguration = run {
|
||||
val base = environment[ScriptingEnvironmentProperties.baseClass]
|
||||
val cfg = base.annotations.filterIsInstance(KotlinScriptDefaultCompilationConfiguration::class.java).flatMap {
|
||||
val cfg = base.annotations.filterIsInstance(KotlinScriptDefaultCompilationConfiguration::class.java).flatMap { ann ->
|
||||
val params = try {
|
||||
it.compilationConfiguration.objectInstance ?: it.compilationConfiguration.primaryConstructor!!.callBy(emptyMap())
|
||||
ann.compilationConfiguration.objectInstance ?: ann.compilationConfiguration.createInstance()
|
||||
} catch (e: Throwable) {
|
||||
throw IllegalArgumentException(ILLEGAL_CONFIG_ANN_ARG, e)
|
||||
}
|
||||
params.forEach {
|
||||
if (it !is Pair<*, *> || it.first !is TypedKey<*>)
|
||||
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: invalid parameter $it")
|
||||
params.forEach { param ->
|
||||
if (param !is Pair<*, *> || param.first !is TypedKey<*>)
|
||||
throw IllegalArgumentException("$ILLEGAL_CONFIG_ANN_ARG: invalid parameter $param")
|
||||
}
|
||||
params as List<Pair<TypedKey<*>, Any?>>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user