Merge commits from both masters and update to 1.5.0-dev-1023
Kotlin/Native base commit: 858a1d77dd0f92d5f926a1ab3d5ab61230758714 Merge branches 'to-native-merge' and 'tmp_branch4merge' into native-merge
This commit is contained in:
+1
-2
@@ -10,12 +10,11 @@
|
|||||||
</option>
|
</option>
|
||||||
<option name="taskNames">
|
<option name="taskNames">
|
||||||
<list>
|
<list>
|
||||||
<option value=":compiler:generateTests" />
|
<option value=":compiler:tests-for-compiler-generator:generateTests" />
|
||||||
<option value=":compiler:tests-java8:generateTests" />
|
<option value=":compiler:tests-java8:generateTests" />
|
||||||
<option value=":compiler:tests-against-klib:generateTests" />
|
<option value=":compiler:tests-against-klib:generateTests" />
|
||||||
<option value=":js:js.tests:generateTests" />
|
<option value=":js:js.tests:generateTests" />
|
||||||
<option value=":core:descriptors.runtime:generateTests" />
|
<option value=":core:descriptors.runtime:generateTests" />
|
||||||
<option value=":compiler:tests-common-new:generateTests" />
|
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
<option name="vmOptions" value="" />
|
<option name="vmOptions" value="" />
|
||||||
|
|||||||
+3
-1
@@ -293,6 +293,7 @@ extra["compilerModules"] = arrayOf(
|
|||||||
":compiler:fir:checkers",
|
":compiler:fir:checkers",
|
||||||
":compiler:fir:entrypoint",
|
":compiler:fir:entrypoint",
|
||||||
":compiler:fir:analysis-tests",
|
":compiler:fir:analysis-tests",
|
||||||
|
":compiler:fir:analysis-tests:legacy-fir-tests",
|
||||||
":wasm:wasm.ir"
|
":wasm:wasm.ir"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -667,6 +668,7 @@ tasks {
|
|||||||
dependsOn(":compiler:fir:raw-fir:psi2fir:test")
|
dependsOn(":compiler:fir:raw-fir:psi2fir:test")
|
||||||
dependsOn(":compiler:fir:raw-fir:light-tree2fir:test")
|
dependsOn(":compiler:fir:raw-fir:light-tree2fir:test")
|
||||||
dependsOn(":compiler:fir:analysis-tests:test")
|
dependsOn(":compiler:fir:analysis-tests:test")
|
||||||
|
dependsOn(":compiler:fir:analysis-tests:legacy-fir-tests:test")
|
||||||
dependsOn(":compiler:fir:fir2ir:test")
|
dependsOn(":compiler:fir:fir2ir:test")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,6 +678,7 @@ tasks {
|
|||||||
":compiler:fir:raw-fir:psi2fir:test",
|
":compiler:fir:raw-fir:psi2fir:test",
|
||||||
":compiler:fir:raw-fir:light-tree2fir:test",
|
":compiler:fir:raw-fir:light-tree2fir:test",
|
||||||
":compiler:fir:analysis-tests:test",
|
":compiler:fir:analysis-tests:test",
|
||||||
|
":compiler:fir:analysis-tests:legacy-fir-tests:test",
|
||||||
":compiler:fir:fir2ir:test",
|
":compiler:fir:fir2ir:test",
|
||||||
":plugins:fir:fir-plugin-prototype:test"
|
":plugins:fir:fir-plugin-prototype:test"
|
||||||
)
|
)
|
||||||
@@ -711,7 +714,6 @@ tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
register("miscCompilerTest") {
|
register("miscCompilerTest") {
|
||||||
dependsOn("wasmCompilerTest")
|
|
||||||
dependsOn("nativeCompilerTest")
|
dependsOn("nativeCompilerTest")
|
||||||
dependsOn("firCompilerTest")
|
dependsOn("firCompilerTest")
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ internal const val PLUGIN_MARKER_SUFFIX = ".gradle.plugin"
|
|||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
fun Project.publishPluginMarkers(withEmptyJars: Boolean = true) {
|
fun Project.publishPluginMarkers(withEmptyJars: Boolean = true) {
|
||||||
|
|
||||||
|
fun Project.isSonatypePublish(): Boolean =
|
||||||
|
hasProperty("isSonatypePublish") && property("isSonatypePublish") as Boolean
|
||||||
|
|
||||||
val pluginDevelopment = extensions.getByType<PluginBundleExtension>()
|
val pluginDevelopment = extensions.getByType<PluginBundleExtension>()
|
||||||
val publishingExtension = extensions.getByType<PublishingExtension>()
|
val publishingExtension = extensions.getByType<PublishingExtension>()
|
||||||
val mainPublication = publishingExtension.publications[KotlinBuildPublishingPlugin.PUBLICATION_NAME] as MavenPublication
|
val mainPublication = publishingExtension.publications[KotlinBuildPublishingPlugin.PUBLICATION_NAME] as MavenPublication
|
||||||
@@ -32,7 +36,12 @@ fun Project.publishPluginMarkers(withEmptyJars: Boolean = true) {
|
|||||||
|
|
||||||
tasks.named<PublishToMavenRepository>(
|
tasks.named<PublishToMavenRepository>(
|
||||||
"publish${markerPublication.name.capitalize(Locale.ROOT)}PublicationTo${KotlinBuildPublishingPlugin.REPOSITORY_NAME}Repository"
|
"publish${markerPublication.name.capitalize(Locale.ROOT)}PublicationTo${KotlinBuildPublishingPlugin.REPOSITORY_NAME}Repository"
|
||||||
).configureRepository()
|
).apply {
|
||||||
|
configureRepository()
|
||||||
|
configure {
|
||||||
|
onlyIf { !isSonatypePublish() }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
|
||||||
|
// This object should help compiling against different ASM versions in different bunch versions
|
||||||
|
object VersionIndependentOpcodes {
|
||||||
|
const val ACC_RECORD = Opcodes.ACC_RECORD
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
|
||||||
|
// This object should help compiling against different ASM versions from different bunch versions
|
||||||
|
object VersionIndependentOpcodes {
|
||||||
|
const val ACC_RECORD = 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.codegen
|
||||||
|
|
||||||
|
fun ClassBuilder.addRecordComponent(name: String, desc: String, signature: String?) {
|
||||||
|
newRecordComponent(name, desc, signature)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.codegen
|
||||||
|
|
||||||
|
fun ClassBuilder.addRecordComponent(name: String, desc: String, signature: String?) {
|
||||||
|
// newRecordComponent(name, desc, signature)
|
||||||
|
}
|
||||||
@@ -223,7 +223,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (JvmAnnotationUtilKt.isJvmRecord(descriptor)) {
|
if (JvmAnnotationUtilKt.isJvmRecord(descriptor)) {
|
||||||
access |= ACC_RECORD;
|
access |= VersionIndependentOpcodes.ACC_RECORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
v.defineClass(
|
v.defineClass(
|
||||||
|
|||||||
-1248
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.codegen.inline.SourceMapper;
|
|||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||||
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
|
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
|
||||||
|
import org.jetbrains.kotlin.config.JvmDefaultMode;
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl;
|
||||||
@@ -83,7 +84,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
|
|
||||||
private final MemberCodegen<?> parentCodegen;
|
private final MemberCodegen<?> parentCodegen;
|
||||||
private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages();
|
private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages();
|
||||||
|
|
||||||
private final Collection<ClassDescriptor> innerClasses = new LinkedHashSet<>();
|
private final Collection<ClassDescriptor> innerClasses = new LinkedHashSet<>();
|
||||||
|
private final Collection<SyntheticInnerClassInfo> syntheticInnerClasses = new LinkedHashSet<>();
|
||||||
|
|
||||||
private ExpressionCodegen clInit;
|
private ExpressionCodegen clInit;
|
||||||
private NameGenerator inlineNameGenerator;
|
private NameGenerator inlineNameGenerator;
|
||||||
@@ -316,6 +319,10 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
genClassOrObject(context, descriptor.getSyntheticDeclaration(), state, this, descriptor);
|
genClassOrObject(context, descriptor.getSyntheticDeclaration(), state, this, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addSyntheticAnonymousInnerClass(SyntheticInnerClassInfo syntheticInnerClassInfo) {
|
||||||
|
syntheticInnerClasses.add(syntheticInnerClassInfo);
|
||||||
|
}
|
||||||
|
|
||||||
private void writeInnerClasses() {
|
private void writeInnerClasses() {
|
||||||
// JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
|
// JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
|
||||||
// for each enclosing class and for each immediate member
|
// for each enclosing class and for each immediate member
|
||||||
@@ -331,6 +338,9 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
for (ClassDescriptor innerClass : innerClasses) {
|
for (ClassDescriptor innerClass : innerClasses) {
|
||||||
writeInnerClass(innerClass);
|
writeInnerClass(innerClass);
|
||||||
}
|
}
|
||||||
|
for (SyntheticInnerClassInfo syntheticInnerClass : syntheticInnerClasses) {
|
||||||
|
v.visitInnerClass(syntheticInnerClass.getInternalName(), null, null, syntheticInnerClass.getFlags());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addParentsToInnerClassesIfNeeded(@NotNull Collection<ClassDescriptor> innerClasses) {
|
protected void addParentsToInnerClassesIfNeeded(@NotNull Collection<ClassDescriptor> innerClasses) {
|
||||||
@@ -376,18 +386,12 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void writeOuterClassAndEnclosingMethod() {
|
protected void writeOuterClassAndEnclosingMethod() {
|
||||||
CodegenContext context = this.context.getParentContext();
|
CodegenContext<?> context = getNonInlineOuterContext(this.context.getParentContext());
|
||||||
|
|
||||||
while (context instanceof InlineLambdaContext) {
|
|
||||||
// If this is a lambda which will be inlined, skip its MethodContext and enclosing ClosureContext
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
context = context.getParentContext().getParentContext();
|
|
||||||
}
|
|
||||||
assert context != null : "Outermost context can't be null: " + this.context;
|
assert context != null : "Outermost context can't be null: " + this.context;
|
||||||
|
|
||||||
Type enclosingAsmType = computeOuterClass(context);
|
Type enclosingAsmType = computeOuterClass(typeMapper, state.getJvmDefaultMode(), element, context);
|
||||||
if (enclosingAsmType != null) {
|
if (enclosingAsmType != null) {
|
||||||
Method method = computeEnclosingMethod(context);
|
Method method = computeEnclosingMethod(typeMapper, context);
|
||||||
|
|
||||||
v.visitOuterClass(
|
v.visitOuterClass(
|
||||||
enclosingAsmType.getInternalName(),
|
enclosingAsmType.getInternalName(),
|
||||||
@@ -397,15 +401,31 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CodegenContext<?> getNonInlineOuterContext(CodegenContext<?> parentContext) {
|
||||||
|
CodegenContext<?> context = parentContext;
|
||||||
|
while (context instanceof InlineLambdaContext) {
|
||||||
|
// If this is a lambda which will be inlined, skip its MethodContext and enclosing ClosureContext
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
context = context.getParentContext().getParentContext();
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Type computeOuterClass(@NotNull CodegenContext<?> context) {
|
public static Type computeOuterClass(
|
||||||
|
@NotNull KotlinTypeMapper typeMapper,
|
||||||
|
@NotNull JvmDefaultMode jvmDefaultMode,
|
||||||
|
@NotNull KtPureElement element,
|
||||||
|
@NotNull CodegenContext<?> context
|
||||||
|
) {
|
||||||
CodegenContext<? extends ClassOrPackageFragmentDescriptor> outermost = context.getClassOrPackageParentContext();
|
CodegenContext<? extends ClassOrPackageFragmentDescriptor> outermost = context.getClassOrPackageParentContext();
|
||||||
if (outermost instanceof ClassContext) {
|
if (outermost instanceof ClassContext) {
|
||||||
ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor();
|
ClassDescriptor classDescriptor = ((ClassContext) outermost).getContextDescriptor();
|
||||||
if (context instanceof MethodContext) {
|
if (context instanceof MethodContext) {
|
||||||
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
||||||
if (isInterface(functionDescriptor.getContainingDeclaration()) && !JvmAnnotationUtilKt
|
if (isInterface(functionDescriptor.getContainingDeclaration()) &&
|
||||||
.isCompiledToJvmDefault(functionDescriptor, state.getJvmDefaultMode())) {
|
!JvmAnnotationUtilKt.isCompiledToJvmDefault(functionDescriptor, jvmDefaultMode)
|
||||||
|
) {
|
||||||
return typeMapper.mapDefaultImpls(classDescriptor);
|
return typeMapper.mapDefaultImpls(classDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,7 +445,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Method computeEnclosingMethod(@NotNull CodegenContext context) {
|
public static Method computeEnclosingMethod(@NotNull KotlinTypeMapper typeMapper, @NotNull CodegenContext context) {
|
||||||
if (context instanceof MethodContext) {
|
if (context instanceof MethodContext) {
|
||||||
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
FunctionDescriptor functionDescriptor = ((MethodContext) context).getFunctionDescriptor();
|
||||||
if ("<clinit>".equals(functionDescriptor.getName().asString())) {
|
if ("<clinit>".equals(functionDescriptor.getName().asString())) {
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ public class PropertyCodegen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (propertyDescriptor.getContainingDeclaration() instanceof ClassDescriptor && JvmAnnotationUtilKt.isJvmRecord((ClassDescriptor) propertyDescriptor.getContainingDeclaration())) {
|
if (propertyDescriptor.getContainingDeclaration() instanceof ClassDescriptor && JvmAnnotationUtilKt.isJvmRecord((ClassDescriptor) propertyDescriptor.getContainingDeclaration())) {
|
||||||
builder.newRecordComponent(name, type.getDescriptor(), signature);
|
ClassBuilderRecordKt.addRecordComponent(builder, name, type.getDescriptor(), signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,680 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* 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.codegen;
|
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import kotlin.Pair;
|
|
||||||
import kotlin.collections.CollectionsKt;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.CodegenContextUtil;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.context.MultifileClassPartContext;
|
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
|
||||||
import org.jetbrains.kotlin.load.java.DescriptorsJvmAbiUtil;
|
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
|
||||||
import org.jetbrains.kotlin.psi.*;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorFactory;
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
|
||||||
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
|
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt;
|
|
||||||
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.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
|
|
||||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
|
||||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
|
||||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getDeprecatedAccessFlag;
|
|
||||||
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.getVisibilityForBackingField;
|
|
||||||
import static org.jetbrains.kotlin.codegen.FunctionCodegen.processInterfaceMethod;
|
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConstOrHasJvmFieldAnnotation;
|
|
||||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isJvmInterface;
|
|
||||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
|
|
||||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*;
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND;
|
|
||||||
import static org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt.isTopLevelInJvmMultifileClass;
|
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface;
|
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.K_PROPERTY_TYPE;
|
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmFieldAnnotation;
|
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.annotations.JvmAnnotationUtilKt.hasJvmSyntheticAnnotation;
|
|
||||||
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
|
|
||||||
|
|
||||||
public class PropertyCodegen {
|
|
||||||
private final GenerationState state;
|
|
||||||
private final ClassBuilder v;
|
|
||||||
private final FunctionCodegen functionCodegen;
|
|
||||||
private final KotlinTypeMapper typeMapper;
|
|
||||||
private final BindingContext bindingContext;
|
|
||||||
private final FieldOwnerContext context;
|
|
||||||
private final MemberCodegen<?> memberCodegen;
|
|
||||||
private final OwnerKind kind;
|
|
||||||
|
|
||||||
public PropertyCodegen(
|
|
||||||
@NotNull FieldOwnerContext context,
|
|
||||||
@NotNull ClassBuilder v,
|
|
||||||
@NotNull FunctionCodegen functionCodegen,
|
|
||||||
@NotNull MemberCodegen<?> memberCodegen
|
|
||||||
) {
|
|
||||||
this.state = functionCodegen.state;
|
|
||||||
this.v = v;
|
|
||||||
this.functionCodegen = functionCodegen;
|
|
||||||
this.typeMapper = state.getTypeMapper();
|
|
||||||
this.bindingContext = state.getBindingContext();
|
|
||||||
this.context = context;
|
|
||||||
this.memberCodegen = memberCodegen;
|
|
||||||
this.kind = context.getContextKind();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void gen(@NotNull KtProperty property) {
|
|
||||||
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, property);
|
|
||||||
if (!(variableDescriptor instanceof PropertyDescriptor)) {
|
|
||||||
throw ExceptionLogger.logDescriptorNotFound(
|
|
||||||
"Property " + property.getName() + " should have a property descriptor: " + variableDescriptor, property
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
|
|
||||||
gen(property, propertyDescriptor, property.getGetter(), property.getSetter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void genDestructuringDeclaration(@NotNull KtDestructuringDeclarationEntry entry) {
|
|
||||||
VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, entry);
|
|
||||||
if (!(variableDescriptor instanceof PropertyDescriptor)) {
|
|
||||||
throw ExceptionLogger.logDescriptorNotFound(
|
|
||||||
"Destructuring declaration entry" + entry.getName() + " should have a property descriptor: " + variableDescriptor, entry
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!UnderscoreUtilKt.isSingleUnderscore(entry)) {
|
|
||||||
genDestructuringDeclaration((PropertyDescriptor) variableDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateInPackageFacade(@NotNull DeserializedPropertyDescriptor deserializedProperty) {
|
|
||||||
assert context instanceof MultifileClassFacadeContext : "should be called only for generating facade: " + context;
|
|
||||||
|
|
||||||
genBackingFieldAndAnnotations(deserializedProperty);
|
|
||||||
|
|
||||||
if (!isConstOrHasJvmFieldAnnotation(deserializedProperty)) {
|
|
||||||
generateGetter(deserializedProperty, null);
|
|
||||||
generateSetter(deserializedProperty, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void gen(
|
|
||||||
@NotNull KtProperty declaration,
|
|
||||||
@NotNull PropertyDescriptor descriptor,
|
|
||||||
@Nullable KtPropertyAccessor getter,
|
|
||||||
@Nullable KtPropertyAccessor setter
|
|
||||||
) {
|
|
||||||
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION ||
|
|
||||||
kind == OwnerKind.DEFAULT_IMPLS || kind == OwnerKind.ERASED_INLINE_CLASS
|
|
||||||
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
|
|
||||||
|
|
||||||
genBackingFieldAndAnnotations(descriptor);
|
|
||||||
|
|
||||||
boolean isDefaultGetterAndSetter = isDefaultAccessor(getter) && isDefaultAccessor(setter);
|
|
||||||
|
|
||||||
if (isAccessorNeeded(descriptor, getter, isDefaultGetterAndSetter)) {
|
|
||||||
generateGetter(descriptor, getter);
|
|
||||||
}
|
|
||||||
if (isAccessorNeeded(descriptor, setter, isDefaultGetterAndSetter)) {
|
|
||||||
generateSetter(descriptor, setter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isDefaultAccessor(@Nullable KtPropertyAccessor accessor) {
|
|
||||||
return accessor == null || !accessor.hasBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void genDestructuringDeclaration(@NotNull PropertyDescriptor descriptor) {
|
|
||||||
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS
|
|
||||||
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
|
|
||||||
|
|
||||||
genBackingFieldAndAnnotations(descriptor);
|
|
||||||
|
|
||||||
generateGetter(descriptor, null);
|
|
||||||
generateSetter(descriptor, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void genBackingFieldAndAnnotations(@NotNull PropertyDescriptor descriptor) {
|
|
||||||
// Fields and '$annotations' methods for non-private const properties are generated in the multi-file facade
|
|
||||||
boolean isBackingFieldOwner = descriptor.isConst() && !DescriptorVisibilities.isPrivate(descriptor.getVisibility())
|
|
||||||
? !(context instanceof MultifileClassPartContext)
|
|
||||||
: CodegenContextUtil.isImplementationOwner(context, descriptor);
|
|
||||||
|
|
||||||
generateBackingField(descriptor, isBackingFieldOwner);
|
|
||||||
generateSyntheticMethodIfNeeded(descriptor, isBackingFieldOwner);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAccessorNeeded(
|
|
||||||
@NotNull PropertyDescriptor descriptor,
|
|
||||||
@Nullable KtPropertyAccessor accessor,
|
|
||||||
boolean isDefaultGetterAndSetter
|
|
||||||
) {
|
|
||||||
return isAccessorNeeded(descriptor, accessor, isDefaultGetterAndSetter, kind);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isReferenceablePropertyWithGetter(@NotNull PropertyDescriptor descriptor) {
|
|
||||||
PsiElement psiElement = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
|
|
||||||
KtDeclaration ktDeclaration = psiElement instanceof KtDeclaration ? (KtDeclaration) psiElement : null;
|
|
||||||
if (ktDeclaration instanceof KtProperty) {
|
|
||||||
KtProperty ktProperty = (KtProperty) ktDeclaration;
|
|
||||||
boolean isDefaultGetterAndSetter =
|
|
||||||
isDefaultAccessor(ktProperty.getGetter()) && isDefaultAccessor(ktProperty.getSetter());
|
|
||||||
return isAccessorNeeded(descriptor, ktProperty.getGetter(), isDefaultGetterAndSetter, OwnerKind.IMPLEMENTATION);
|
|
||||||
} else if (ktDeclaration instanceof KtParameter) {
|
|
||||||
return isAccessorNeeded(descriptor, null, true, OwnerKind.IMPLEMENTATION);
|
|
||||||
} else {
|
|
||||||
return isAccessorNeeded(descriptor, null, false, OwnerKind.IMPLEMENTATION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter
|
|
||||||
* for any reason
|
|
||||||
*
|
|
||||||
* @see JvmCodegenUtil#couldUseDirectAccessToProperty
|
|
||||||
*/
|
|
||||||
private static boolean isAccessorNeeded(
|
|
||||||
@NotNull PropertyDescriptor descriptor,
|
|
||||||
@Nullable KtPropertyAccessor accessor,
|
|
||||||
boolean isDefaultGetterAndSetter,
|
|
||||||
OwnerKind kind
|
|
||||||
) {
|
|
||||||
if (isConstOrHasJvmFieldAnnotation(descriptor)) return false;
|
|
||||||
|
|
||||||
boolean isDefaultAccessor = isDefaultAccessor(accessor);
|
|
||||||
|
|
||||||
// Don't generate accessors for interface properties with default accessors in DefaultImpls
|
|
||||||
if (kind == OwnerKind.DEFAULT_IMPLS && isDefaultAccessor) return false;
|
|
||||||
|
|
||||||
// Delegated or extension properties can only be referenced via accessors
|
|
||||||
if (descriptor.isDelegated() || descriptor.getExtensionReceiverParameter() != null) return true;
|
|
||||||
|
|
||||||
// Companion object properties should have accessors for non-private properties because these properties can be referenced
|
|
||||||
// via getter/setter. But these accessors getter/setter are not required for private properties that have a default getter
|
|
||||||
// and setter, in this case, the property can always be accessed through the accessor 'access<property name>$cp' and avoid some
|
|
||||||
// useless indirection by using others accessors.
|
|
||||||
if (isCompanionObject(descriptor.getContainingDeclaration())) {
|
|
||||||
if (DescriptorVisibilities.isPrivate(descriptor.getVisibility()) && isDefaultGetterAndSetter) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-const properties from multifile classes have accessors regardless of visibility
|
|
||||||
if (isTopLevelInJvmMultifileClass(descriptor)) return true;
|
|
||||||
|
|
||||||
// Private class properties have accessors only in cases when those accessors are non-trivial
|
|
||||||
if (DescriptorVisibilities.isPrivate(descriptor.getVisibility())) {
|
|
||||||
return !isDefaultAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-private properties with private setter should not be generated for trivial properties
|
|
||||||
// as the class will use direct field access instead
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
if (accessor != null && accessor.isSetter() && DescriptorVisibilities.isPrivate(descriptor.getSetter().getVisibility())) {
|
|
||||||
return !isDefaultAccessor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Non-public API (private and internal) primary vals of inline classes don't have getter
|
|
||||||
if (InlineClassesUtilsKt.isUnderlyingPropertyOfInlineClass(descriptor) && !descriptor.getVisibility().isPublicAPI()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean areAccessorsNeededForPrimaryConstructorProperty(
|
|
||||||
@NotNull PropertyDescriptor descriptor,
|
|
||||||
@NotNull OwnerKind kind
|
|
||||||
) {
|
|
||||||
if (hasJvmFieldAnnotation(descriptor)) return false;
|
|
||||||
if (kind == OwnerKind.ERASED_INLINE_CLASS) return false;
|
|
||||||
|
|
||||||
DescriptorVisibility visibility = descriptor.getVisibility();
|
|
||||||
if (InlineClassesUtilsKt.isInlineClass(descriptor.getContainingDeclaration())) {
|
|
||||||
return visibility.isPublicAPI();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return !DescriptorVisibilities.isPrivate(visibility);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generatePrimaryConstructorProperty(@NotNull PropertyDescriptor descriptor) {
|
|
||||||
genBackingFieldAndAnnotations(descriptor);
|
|
||||||
|
|
||||||
if (areAccessorsNeededForPrimaryConstructorProperty(descriptor, context.getContextKind())) {
|
|
||||||
generateGetter(descriptor, null);
|
|
||||||
generateSetter(descriptor, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateConstructorPropertyAsMethodForAnnotationClass(
|
|
||||||
@NotNull KtParameter parameter,
|
|
||||||
@NotNull PropertyDescriptor descriptor,
|
|
||||||
@Nullable FunctionDescriptor expectedAnnotationConstructor
|
|
||||||
) {
|
|
||||||
JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor);
|
|
||||||
Method asmMethod = signature.getAsmMethod();
|
|
||||||
MethodVisitor mv = v.newMethod(
|
|
||||||
JvmDeclarationOriginKt.OtherOrigin(parameter, descriptor),
|
|
||||||
ACC_PUBLIC | ACC_ABSTRACT,
|
|
||||||
asmMethod.getName(),
|
|
||||||
asmMethod.getDescriptor(),
|
|
||||||
signature.getGenericsSignature(),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
PropertyGetterDescriptor getter = descriptor.getGetter();
|
|
||||||
assert getter != null : "Annotation property should have a getter: " + descriptor;
|
|
||||||
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, getter, asmMethod);
|
|
||||||
AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(getter, asmMethod.getReturnType(), null);
|
|
||||||
|
|
||||||
KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor);
|
|
||||||
if (defaultValue != null) {
|
|
||||||
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(
|
|
||||||
defaultValue, bindingContext, true, state.getShouldInlineConstVals());
|
|
||||||
assert !state.getClassBuilderMode().generateBodies || constant != null
|
|
||||||
: "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
|
|
||||||
if (constant != null) {
|
|
||||||
AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(mv, memberCodegen, state);
|
|
||||||
annotationCodegen.generateAnnotationDefaultValue(constant, descriptor.getType());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mv.visitEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
private KtExpression loadAnnotationArgumentDefaultValue(
|
|
||||||
@NotNull KtParameter ktParameter,
|
|
||||||
@NotNull PropertyDescriptor descriptor,
|
|
||||||
@Nullable FunctionDescriptor expectedAnnotationConstructor
|
|
||||||
) {
|
|
||||||
KtExpression value = ktParameter.getDefaultValue();
|
|
||||||
if (value != null) return value;
|
|
||||||
|
|
||||||
if (expectedAnnotationConstructor != null) {
|
|
||||||
ValueParameterDescriptor expectedParameter = CollectionsKt.single(
|
|
||||||
expectedAnnotationConstructor.getValueParameters(), parameter -> parameter.getName().equals(descriptor.getName())
|
|
||||||
);
|
|
||||||
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(expectedParameter);
|
|
||||||
if (!(element instanceof KtParameter)) {
|
|
||||||
state.getDiagnostics().report(EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND.on(ktParameter));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ((KtParameter) element).getDefaultValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateBackingField(@NotNull PropertyDescriptor descriptor, boolean isBackingFieldOwner) {
|
|
||||||
if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS ||
|
|
||||||
kind == OwnerKind.ERASED_INLINE_CLASS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object defaultValue;
|
|
||||||
if (descriptor.isDelegated()) {
|
|
||||||
defaultValue = null;
|
|
||||||
}
|
|
||||||
else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
|
|
||||||
if (shouldWriteFieldInitializer(descriptor)) {
|
|
||||||
ConstantValue<?> initializer = descriptor.getCompileTimeInitializer();
|
|
||||||
defaultValue = initializer == null ? null : initializer.getValue();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
defaultValue = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
generateBackingField(descriptor, descriptor.isDelegated(), defaultValue, isBackingFieldOwner);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
|
|
||||||
// accessible via reflection, and 'deprecated' and 'synthetic' flags prevent this method from being called accidentally
|
|
||||||
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, boolean isBackingFieldOwner) {
|
|
||||||
Annotations annotations = descriptor.getAnnotations();
|
|
||||||
if (annotations.isEmpty()) return;
|
|
||||||
|
|
||||||
Method signature = typeMapper.mapSyntheticMethodForPropertyAnnotations(descriptor);
|
|
||||||
if (kind != OwnerKind.DEFAULT_IMPLS && CodegenContextUtil.isImplementationOwner(context, descriptor)) {
|
|
||||||
v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, signature);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBackingFieldOwner) {
|
|
||||||
if (!isInterface(context.getContextDescriptor()) ||
|
|
||||||
processInterfaceMethod(descriptor, kind, false, true, state.getJvmDefaultMode())) {
|
|
||||||
memberCodegen.generateSyntheticAnnotationsMethod(descriptor, signature, annotations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateBackingField(
|
|
||||||
@NotNull PropertyDescriptor propertyDescriptor,
|
|
||||||
boolean isDelegate,
|
|
||||||
@Nullable Object defaultValue,
|
|
||||||
boolean isBackingFieldOwner
|
|
||||||
) {
|
|
||||||
FieldDescriptor annotatedField = isDelegate ? propertyDescriptor.getDelegateField() : propertyDescriptor.getBackingField();
|
|
||||||
|
|
||||||
int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
|
|
||||||
|
|
||||||
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) {
|
|
||||||
modifiers |= flagAnnotation.getJvmFlag(annotatedField);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kind == OwnerKind.PACKAGE) {
|
|
||||||
modifiers |= ACC_STATIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!propertyDescriptor.isLateInit() && (!propertyDescriptor.isVar() || isDelegate)) {
|
|
||||||
modifiers |= ACC_FINAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasJvmSyntheticAnnotation(propertyDescriptor)) {
|
|
||||||
modifiers |= ACC_SYNTHETIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
KotlinType kotlinType = isDelegate ? getDelegateTypeForProperty(propertyDescriptor, bindingContext) : propertyDescriptor.getType();
|
|
||||||
Type type = typeMapper.mapType(kotlinType);
|
|
||||||
|
|
||||||
ClassBuilder builder = v;
|
|
||||||
|
|
||||||
FieldOwnerContext backingFieldContext = context;
|
|
||||||
List<String> additionalVisibleAnnotations = Collections.emptyList();
|
|
||||||
if (DescriptorAsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
|
|
||||||
modifiers |= ACC_STATIC;
|
|
||||||
|
|
||||||
if (DescriptorsJvmAbiUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) {
|
|
||||||
ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
|
|
||||||
builder = codegen.v;
|
|
||||||
backingFieldContext = codegen.context;
|
|
||||||
if (DescriptorVisibilities.isPrivate(((ClassDescriptor) propertyDescriptor.getContainingDeclaration()).getVisibility())) {
|
|
||||||
modifiers |= ACC_DEPRECATED;
|
|
||||||
additionalVisibleAnnotations = Collections.singletonList(CodegenUtilKt.JAVA_LANG_DEPRECATED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
modifiers |= getVisibilityForBackingField(propertyDescriptor, isDelegate);
|
|
||||||
|
|
||||||
if (DescriptorAsmUtil.isPropertyWithBackingFieldCopyInOuterClass(propertyDescriptor)) {
|
|
||||||
ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen();
|
|
||||||
parentBodyCodegen.addCompanionObjectPropertyToCopy(propertyDescriptor, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = backingFieldContext.getFieldName(propertyDescriptor, isDelegate);
|
|
||||||
|
|
||||||
v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, new Pair<>(type, name));
|
|
||||||
|
|
||||||
if (isBackingFieldOwner) {
|
|
||||||
String signature = isDelegate ? null : typeMapper.mapFieldSignature(kotlinType, propertyDescriptor);
|
|
||||||
FieldVisitor fv = builder.newField(
|
|
||||||
JvmDeclarationOriginKt.OtherOrigin(propertyDescriptor), modifiers, name, type.getDescriptor(),
|
|
||||||
signature, defaultValue
|
|
||||||
);
|
|
||||||
|
|
||||||
if (annotatedField != null) {
|
|
||||||
// Don't emit nullability annotations for backing field if:
|
|
||||||
// - backing field is synthetic;
|
|
||||||
// - property is lateinit (since corresponding field is actually nullable).
|
|
||||||
boolean skipNullabilityAnnotations =
|
|
||||||
(modifiers & ACC_SYNTHETIC) != 0 ||
|
|
||||||
propertyDescriptor.isLateInit();
|
|
||||||
AnnotationCodegen.forField(fv, memberCodegen, state, skipNullabilityAnnotations)
|
|
||||||
.genAnnotations(annotatedField, type, propertyDescriptor.getType(), null, additionalVisibleAnnotations);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyDescriptor.getContainingDeclaration() instanceof ClassDescriptor && JvmAnnotationUtilKt.isJvmRecord((ClassDescriptor) propertyDescriptor.getContainingDeclaration())) {
|
|
||||||
// builder.newRecordComponent(name, type.getDescriptor(), signature);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static KotlinType getDelegateTypeForProperty(
|
|
||||||
@NotNull PropertyDescriptor propertyDescriptor,
|
|
||||||
@NotNull BindingContext bindingContext
|
|
||||||
) {
|
|
||||||
ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall =
|
|
||||||
bindingContext.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, propertyDescriptor);
|
|
||||||
|
|
||||||
KtProperty property = (KtProperty) DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
|
|
||||||
KtExpression delegateExpression = property != null ? property.getDelegateExpression() : null;
|
|
||||||
|
|
||||||
KotlinType delegateType;
|
|
||||||
if (provideDelegateResolvedCall != null) {
|
|
||||||
delegateType = provideDelegateResolvedCall.getResultingDescriptor().getReturnType();
|
|
||||||
}
|
|
||||||
else if (delegateExpression != null) {
|
|
||||||
delegateType = bindingContext.getType(delegateExpression);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
delegateType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delegateType == null) {
|
|
||||||
// Delegation convention is unresolved
|
|
||||||
delegateType = ErrorUtils.createErrorType("Delegate type");
|
|
||||||
}
|
|
||||||
return delegateType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
|
|
||||||
if (!descriptor.isConst() &&
|
|
||||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//final field of primitive or String type
|
|
||||||
if (!descriptor.isVar()) {
|
|
||||||
Type type = typeMapper.mapType(descriptor);
|
|
||||||
return AsmUtil.isPrimitive(type) || "java.lang.String".equals(type.getClassName());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateGetter(@NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor getter) {
|
|
||||||
generateAccessor(
|
|
||||||
getter,
|
|
||||||
descriptor.getGetter() != null ? descriptor.getGetter() : DescriptorFactory.createDefaultGetter(
|
|
||||||
descriptor, Annotations.Companion.getEMPTY()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateSetter(@NotNull PropertyDescriptor descriptor, @Nullable KtPropertyAccessor setter) {
|
|
||||||
if (!descriptor.isVar()) return;
|
|
||||||
|
|
||||||
generateAccessor(
|
|
||||||
setter,
|
|
||||||
descriptor.getSetter() != null ? descriptor.getSetter() : DescriptorFactory.createDefaultSetter(
|
|
||||||
descriptor, Annotations.Companion.getEMPTY(), Annotations.Companion.getEMPTY()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateAccessor(@Nullable KtPropertyAccessor accessor, @NotNull PropertyAccessorDescriptor descriptor) {
|
|
||||||
if (context instanceof MultifileClassFacadeContext &&
|
|
||||||
(DescriptorVisibilities.isPrivate(descriptor.getVisibility()) ||
|
|
||||||
DescriptorAsmUtil.getVisibilityAccessFlag(descriptor) == Opcodes.ACC_PRIVATE)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionGenerationStrategy strategy;
|
|
||||||
if (accessor == null || !accessor.hasBody()) {
|
|
||||||
if (descriptor.getCorrespondingProperty().isDelegated()) {
|
|
||||||
strategy = new DelegatedPropertyAccessorStrategy(state, descriptor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strategy = new DefaultPropertyAccessorStrategy(state, descriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strategy = new FunctionGenerationStrategy.FunctionDefault(state, accessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
functionCodegen.generateMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), descriptor, strategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DefaultPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
|
|
||||||
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
|
|
||||||
|
|
||||||
public DefaultPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
|
|
||||||
super(state);
|
|
||||||
propertyAccessorDescriptor = descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
|
||||||
InstructionAdapter v = codegen.v;
|
|
||||||
PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty();
|
|
||||||
StackValue property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
|
||||||
|
|
||||||
PsiElement jetProperty = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
|
|
||||||
if (jetProperty instanceof KtProperty || jetProperty instanceof KtParameter) {
|
|
||||||
codegen.markLineNumber((KtElement) jetProperty, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyAccessorDescriptor instanceof PropertyGetterDescriptor) {
|
|
||||||
Type type = signature.getReturnType();
|
|
||||||
property.put(type, v);
|
|
||||||
v.areturn(type);
|
|
||||||
}
|
|
||||||
else if (propertyAccessorDescriptor instanceof PropertySetterDescriptor) {
|
|
||||||
List<ValueParameterDescriptor> valueParameters = propertyAccessorDescriptor.getValueParameters();
|
|
||||||
assert valueParameters.size() == 1 : "Property setter should have only one value parameter but has " + propertyAccessorDescriptor;
|
|
||||||
int parameterIndex = codegen.lookupLocalIndex(valueParameters.get(0));
|
|
||||||
assert parameterIndex >= 0 : "Local index for setter parameter should be positive or zero: " + propertyAccessorDescriptor;
|
|
||||||
Type type = codegen.typeMapper.mapType(propertyDescriptor);
|
|
||||||
property.store(StackValue.local(parameterIndex, type), codegen.v);
|
|
||||||
v.visitInsn(RETURN);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalStateException("Unknown property accessor: " + propertyAccessorDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StackValue invokeDelegatedPropertyConventionMethod(
|
|
||||||
@NotNull ExpressionCodegen codegen,
|
|
||||||
@NotNull ResolvedCall<FunctionDescriptor> resolvedCall,
|
|
||||||
@NotNull StackValue receiver,
|
|
||||||
@NotNull PropertyDescriptor propertyDescriptor
|
|
||||||
) {
|
|
||||||
codegen.tempVariables.put(
|
|
||||||
resolvedCall.getCall().getValueArguments().get(1).asElement(),
|
|
||||||
getDelegatedPropertyMetadata(propertyDescriptor, codegen.getBindingContext())
|
|
||||||
);
|
|
||||||
|
|
||||||
return codegen.invokeFunction(resolvedCall, receiver);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isDelegatedPropertyWithOptimizedMetadata(
|
|
||||||
@NotNull VariableDescriptorWithAccessors descriptor,
|
|
||||||
@NotNull BindingContext bindingContext
|
|
||||||
) {
|
|
||||||
return Boolean.TRUE == bindingContext.get(DELEGATED_PROPERTY_WITH_OPTIMIZED_METADATA, descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @NotNull StackValue getOptimizedDelegatedPropertyMetadataValue() {
|
|
||||||
return StackValue.constant(null, K_PROPERTY_TYPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static StackValue getDelegatedPropertyMetadata(
|
|
||||||
@NotNull VariableDescriptorWithAccessors descriptor,
|
|
||||||
@NotNull BindingContext bindingContext
|
|
||||||
) {
|
|
||||||
if (isDelegatedPropertyWithOptimizedMetadata(descriptor, bindingContext)) {
|
|
||||||
return getOptimizedDelegatedPropertyMetadataValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
Type owner = bindingContext.get(DELEGATED_PROPERTY_METADATA_OWNER, descriptor);
|
|
||||||
assert owner != null : "Delegated property owner not found: " + descriptor;
|
|
||||||
|
|
||||||
List<VariableDescriptorWithAccessors> allDelegatedProperties = bindingContext.get(DELEGATED_PROPERTIES_WITH_METADATA, owner);
|
|
||||||
int index = allDelegatedProperties == null ? -1 : allDelegatedProperties.indexOf(descriptor);
|
|
||||||
if (index < 0) {
|
|
||||||
throw new AssertionError("Delegated property not found in " + owner + ": " + descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
StackValue.Field array = StackValue.field(
|
|
||||||
Type.getType("[" + K_PROPERTY_TYPE), owner, JvmAbi.DELEGATED_PROPERTIES_ARRAY_NAME, true, StackValue.none()
|
|
||||||
);
|
|
||||||
return StackValue.arrayElement(K_PROPERTY_TYPE, null, array, StackValue.constant(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DelegatedPropertyAccessorStrategy extends FunctionGenerationStrategy.CodegenBased {
|
|
||||||
private final PropertyAccessorDescriptor propertyAccessorDescriptor;
|
|
||||||
|
|
||||||
public DelegatedPropertyAccessorStrategy(@NotNull GenerationState state, @NotNull PropertyAccessorDescriptor descriptor) {
|
|
||||||
super(state);
|
|
||||||
this.propertyAccessorDescriptor = descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
|
||||||
InstructionAdapter v = codegen.v;
|
|
||||||
|
|
||||||
BindingContext bindingContext = state.getBindingContext();
|
|
||||||
ResolvedCall<FunctionDescriptor> resolvedCall =
|
|
||||||
bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, propertyAccessorDescriptor);
|
|
||||||
assert resolvedCall != null : "Resolve call should be recorded for delegate call " + signature.toString();
|
|
||||||
|
|
||||||
PropertyDescriptor propertyDescriptor = propertyAccessorDescriptor.getCorrespondingProperty();
|
|
||||||
StackValue.Property property = codegen.intermediateValueForProperty(propertyDescriptor, true, null, StackValue.LOCAL_0);
|
|
||||||
StackValue.Property delegate = property.getDelegateOrNull();
|
|
||||||
assert delegate != null : "No delegate for delegated property: " + propertyDescriptor;
|
|
||||||
StackValue lastValue = invokeDelegatedPropertyConventionMethod(codegen, resolvedCall, delegate, propertyDescriptor);
|
|
||||||
Type asmType = signature.getReturnType();
|
|
||||||
KotlinType kotlinReturnType = propertyAccessorDescriptor.getOriginal().getReturnType();
|
|
||||||
lastValue.put(asmType, kotlinReturnType, v);
|
|
||||||
v.areturn(asmType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void genDelegate(@NotNull PropertyDescriptor delegate, @NotNull PropertyDescriptor delegateTo, @NotNull StackValue field) {
|
|
||||||
ClassDescriptor toClass = (ClassDescriptor) delegateTo.getContainingDeclaration();
|
|
||||||
|
|
||||||
PropertyGetterDescriptor getter = delegate.getGetter();
|
|
||||||
if (getter != null) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
functionCodegen.genDelegate(getter, delegateTo.getGetter().getOriginal(), toClass, field);
|
|
||||||
}
|
|
||||||
|
|
||||||
PropertySetterDescriptor setter = delegate.getSetter();
|
|
||||||
if (setter != null) {
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
functionCodegen.genDelegate(setter, delegateTo.getSetter().getOriginal(), toClass, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,6 +20,8 @@ import kotlin.text.StringsKt;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||||
import org.jetbrains.kotlin.codegen.context.ClassContext;
|
import org.jetbrains.kotlin.codegen.context.ClassContext;
|
||||||
|
import org.jetbrains.kotlin.codegen.context.CodegenContext;
|
||||||
|
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
@@ -62,6 +64,7 @@ public class SamWrapperCodegen {
|
|||||||
private final SamType samType;
|
private final SamType samType;
|
||||||
private final MemberCodegen<?> parentCodegen;
|
private final MemberCodegen<?> parentCodegen;
|
||||||
private final int visibility;
|
private final int visibility;
|
||||||
|
private final int classFlags;
|
||||||
public static final String SAM_WRAPPER_SUFFIX = "$0";
|
public static final String SAM_WRAPPER_SUFFIX = "$0";
|
||||||
|
|
||||||
public SamWrapperCodegen(
|
public SamWrapperCodegen(
|
||||||
@@ -76,6 +79,7 @@ public class SamWrapperCodegen {
|
|||||||
this.samType = samType;
|
this.samType = samType;
|
||||||
this.parentCodegen = parentCodegen;
|
this.parentCodegen = parentCodegen;
|
||||||
visibility = isInsideInline ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
|
visibility = isInsideInline ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
|
||||||
|
classFlags = visibility | ACC_FINAL | ACC_SUPER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -121,7 +125,7 @@ public class SamWrapperCodegen {
|
|||||||
cv.defineClass(
|
cv.defineClass(
|
||||||
file,
|
file,
|
||||||
state.getClassFileVersion(),
|
state.getClassFileVersion(),
|
||||||
ACC_FINAL | ACC_SUPER | visibility,
|
classFlags,
|
||||||
asmType.getInternalName(),
|
asmType.getInternalName(),
|
||||||
null,
|
null,
|
||||||
OBJECT_TYPE.getInternalName(),
|
OBJECT_TYPE.getInternalName(),
|
||||||
@@ -131,6 +135,8 @@ public class SamWrapperCodegen {
|
|||||||
|
|
||||||
WriteAnnotationUtilKt.writeSyntheticClassMetadata(cv, state);
|
WriteAnnotationUtilKt.writeSyntheticClassMetadata(cv, state);
|
||||||
|
|
||||||
|
generateInnerClassInformation(file, asmType, cv);
|
||||||
|
|
||||||
// e.g. ASM type for Function2
|
// e.g. ASM type for Function2
|
||||||
Type functionAsmType = typeMapper.mapType(functionType);
|
Type functionAsmType = typeMapper.mapType(functionType);
|
||||||
|
|
||||||
@@ -160,6 +166,24 @@ public class SamWrapperCodegen {
|
|||||||
return asmType;
|
return asmType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateInnerClassInformation(@NotNull KtFile file, Type asmType, ClassBuilder cv) {
|
||||||
|
parentCodegen.addSyntheticAnonymousInnerClass(new SyntheticInnerClassInfo(asmType.getInternalName(), classFlags));
|
||||||
|
FieldOwnerContext<?> parentContext = parentCodegen.context;
|
||||||
|
CodegenContext<?> outerContext = MemberCodegen.getNonInlineOuterContext(parentContext);
|
||||||
|
assert outerContext != null :
|
||||||
|
"Outer context for SAM wrapper " + asmType.getInternalName() + " is null, parentContext:" + parentContext;
|
||||||
|
Type outerClassType = MemberCodegen.computeOuterClass(state.getTypeMapper(), state.getJvmDefaultMode(), file, outerContext);
|
||||||
|
assert outerClassType != null :
|
||||||
|
"Outer class for SAM wrapper " + asmType.getInternalName() + " is null, parentContext:" + parentContext;
|
||||||
|
Method enclosingMethod = MemberCodegen.computeEnclosingMethod(state.getTypeMapper(), outerContext);
|
||||||
|
cv.visitOuterClass(
|
||||||
|
outerClassType.getInternalName(),
|
||||||
|
enclosingMethod == null ? null : enclosingMethod.getName(),
|
||||||
|
enclosingMethod == null ? null : enclosingMethod.getDescriptor()
|
||||||
|
);
|
||||||
|
cv.visitInnerClass(asmType.getInternalName(), null, null, classFlags);
|
||||||
|
}
|
||||||
|
|
||||||
private void generateConstructor(Type ownerType, Type functionType, ClassBuilder cv) {
|
private void generateConstructor(Type ownerType, Type functionType, ClassBuilder cv) {
|
||||||
MethodVisitor mv = cv.newMethod(JvmDeclarationOriginKt.OtherOrigin(samType.getClassDescriptor()),
|
MethodVisitor mv = cv.newMethod(JvmDeclarationOriginKt.OtherOrigin(samType.getClassDescriptor()),
|
||||||
visibility, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
|
visibility, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.codegen
|
||||||
|
|
||||||
|
data class SyntheticInnerClassInfo(val internalName: String, val flags: Int)
|
||||||
+1
-1
@@ -1113,7 +1113,7 @@ inline fun withInstructionAdapter(block: InstructionAdapter.() -> Unit): InsnLis
|
|||||||
return tmpMethodNode.instructions
|
return tmpMethodNode.instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Type.normalize() =
|
fun Type.normalize() =
|
||||||
when (sort) {
|
when (sort) {
|
||||||
Type.ARRAY, Type.OBJECT -> AsmTypes.OBJECT_TYPE
|
Type.ARRAY, Type.OBJECT -> AsmTypes.OBJECT_TYPE
|
||||||
else -> this
|
else -> this
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
|
|||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.incremental.components.Position
|
import org.jetbrains.kotlin.incremental.components.Position
|
||||||
import org.jetbrains.kotlin.incremental.components.ScopeKind
|
import org.jetbrains.kotlin.incremental.components.ScopeKind
|
||||||
@@ -522,10 +523,15 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP())
|
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP())
|
||||||
}
|
}
|
||||||
|
|
||||||
val asmMethod = if (callDefault)
|
var asmMethod = mapMethod(callDefault)
|
||||||
state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompiler.contextKind)
|
if (asmMethod.name.contains("-") &&
|
||||||
else
|
!state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_INLINE_CLASSES_MANGLING_SCHEME) &&
|
||||||
mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
|
classFileContainsMethod(functionDescriptor, state, asmMethod) == false
|
||||||
|
) {
|
||||||
|
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = true
|
||||||
|
asmMethod = mapMethod(callDefault)
|
||||||
|
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = false
|
||||||
|
}
|
||||||
|
|
||||||
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
|
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
|
||||||
if (!isBuiltInArrayIntrinsic(functionDescriptor) && !descriptorIsDeserialized(directMember)) {
|
if (!isBuiltInArrayIntrinsic(functionDescriptor) && !descriptorIsDeserialized(directMember)) {
|
||||||
@@ -537,6 +543,10 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature)
|
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun mapMethod(callDefault: Boolean): Method =
|
||||||
|
if (callDefault) state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompiler.contextKind)
|
||||||
|
else mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
internal fun createSpecialInlineMethodNodeFromBinaries(functionDescriptor: FunctionDescriptor, state: GenerationState): MethodNode {
|
internal fun createSpecialInlineMethodNodeFromBinaries(functionDescriptor: FunctionDescriptor, state: GenerationState): MethodNode {
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ class GenerationState private constructor(
|
|||||||
?: if (languageVersionSettings.languageVersion >= LanguageVersion.LATEST_STABLE) JvmMetadataVersion.INSTANCE
|
?: if (languageVersionSettings.languageVersion >= LanguageVersion.LATEST_STABLE) JvmMetadataVersion.INSTANCE
|
||||||
else JvmMetadataVersion(1, 1, 18)
|
else JvmMetadataVersion(1, 1, 18)
|
||||||
|
|
||||||
val isIrWithStableAbi = configuration.getBoolean(JVMConfigurationKeys.IS_IR_WITH_STABLE_ABI)
|
val abiStability = configuration.get(JVMConfigurationKeys.ABI_STABILITY)
|
||||||
|
|
||||||
val globalSerializationBindings = JvmSerializationBindings()
|
val globalSerializationBindings = JvmSerializationBindings()
|
||||||
var mapInlineClass: (ClassDescriptor) -> Type = { descriptor -> typeMapper.mapType(descriptor.defaultType) }
|
var mapInlineClass: (ClassDescriptor) -> Type = { descriptor -> typeMapper.mapType(descriptor.defaultType) }
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ dependencies {
|
|||||||
testCompile(projectTests(":compiler:fir:raw-fir:psi2fir"))
|
testCompile(projectTests(":compiler:fir:raw-fir:psi2fir"))
|
||||||
testCompile(projectTests(":compiler:fir:raw-fir:light-tree2fir"))
|
testCompile(projectTests(":compiler:fir:raw-fir:light-tree2fir"))
|
||||||
testCompile(projectTests(":compiler:fir:fir2ir"))
|
testCompile(projectTests(":compiler:fir:fir2ir"))
|
||||||
testCompile(projectTests(":compiler:fir:analysis-tests"))
|
testCompile(projectTests(":compiler:fir:analysis-tests:legacy-fir-tests"))
|
||||||
testCompile(projectTests(":compiler:visualizer"))
|
testCompile(projectTests(":compiler:visualizer"))
|
||||||
testCompile(projectTests(":generators:test-generator"))
|
testCompile(projectTests(":generators:test-generator"))
|
||||||
testCompile(project(":compiler:ir.ir2cfg"))
|
testCompile(project(":compiler:ir.ir2cfg"))
|
||||||
@@ -99,8 +99,5 @@ projectTest(parallel = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val generateTestData by generator("org.jetbrains.kotlin.generators.tests.GenerateCompilerTestDataKt")
|
val generateTestData by generator("org.jetbrains.kotlin.generators.tests.GenerateCompilerTestDataKt")
|
||||||
val generateTests by generator("org.jetbrains.kotlin.generators.tests.GenerateCompilerTestsKt") {
|
|
||||||
dependsOn(generateTestData)
|
|
||||||
}
|
|
||||||
|
|
||||||
testsJar()
|
testsJar()
|
||||||
|
|||||||
+11
-9
@@ -95,18 +95,20 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
|||||||
var irCheckLocalNames: Boolean by FreezableVar(false)
|
var irCheckLocalNames: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
@Argument(
|
@Argument(
|
||||||
value = "-Xallow-jvm-ir-dependencies",
|
value = "-Xallow-unstable-dependencies",
|
||||||
description = "When not using the IR backend, do not report errors on those classes in dependencies, " +
|
description = "Do not report errors on classes in dependencies, which were compiled by an unstable version of the Kotlin compiler"
|
||||||
"which were compiled by the IR backend"
|
|
||||||
)
|
)
|
||||||
var allowJvmIrDependencies: Boolean by FreezableVar(false)
|
var allowUnstableDependencies: Boolean by FreezableVar(false)
|
||||||
|
|
||||||
@Argument(
|
@Argument(
|
||||||
value = "-Xir-binary-with-stable-abi",
|
value = "-Xabi-stability",
|
||||||
description = "When using the IR backend, produce binaries which can be read by non-IR backend.\n" +
|
valueDescription = "{stable|unstable}",
|
||||||
"The author is responsible for verifying that the resulting binaries do indeed have the correct ABI"
|
description = "When using unstable compiler features such as FIR, use 'stable' to mark generated class files as stable\n" +
|
||||||
|
"to prevent diagnostics from stable compilers at the call site.\n" +
|
||||||
|
"When using the JVM IR backend, conversely, use 'unstable' to mark generated class files as unstable\n" +
|
||||||
|
"to force diagnostics to be reported."
|
||||||
)
|
)
|
||||||
var isIrWithStableAbi: Boolean by FreezableVar(false)
|
var abiStability: String? by FreezableVar(null)
|
||||||
|
|
||||||
@Argument(
|
@Argument(
|
||||||
value = "-Xir-do-not-clear-binding-context",
|
value = "-Xir-do-not-clear-binding-context",
|
||||||
@@ -446,7 +448,7 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
|
|||||||
result[JvmAnalysisFlags.suppressMissingBuiltinsError] = suppressMissingBuiltinsError
|
result[JvmAnalysisFlags.suppressMissingBuiltinsError] = suppressMissingBuiltinsError
|
||||||
result[JvmAnalysisFlags.irCheckLocalNames] = irCheckLocalNames
|
result[JvmAnalysisFlags.irCheckLocalNames] = irCheckLocalNames
|
||||||
result[JvmAnalysisFlags.enableJvmPreview] = enableJvmPreview
|
result[JvmAnalysisFlags.enableJvmPreview] = enableJvmPreview
|
||||||
result[AnalysisFlags.reportErrorsOnIrDependencies] = !useIR && !useFir && !allowJvmIrDependencies
|
result[AnalysisFlags.allowUnstableDependencies] = allowUnstableDependencies || useFir
|
||||||
result[JvmAnalysisFlags.disableUltraLightClasses] = disableUltraLightClasses
|
result[JvmAnalysisFlags.disableUltraLightClasses] = disableUltraLightClasses
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -182,11 +182,19 @@ class AnalyzerWithCompilerReport(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diagnostics.any { it.factory == Errors.IR_COMPILED_CLASS }) {
|
if (diagnostics.any { it.factory == Errors.IR_WITH_UNSTABLE_ABI_COMPILED_CLASS }) {
|
||||||
messageCollector.report(
|
messageCollector.report(
|
||||||
ERROR,
|
ERROR,
|
||||||
"Classes compiled by a new Kotlin compiler backend were found in dependencies. " +
|
"Classes compiled by an unstable version of the Kotlin compiler were found in dependencies. " +
|
||||||
"Remove them from the classpath or use '-Xallow-jvm-ir-dependencies' to suppress errors"
|
"Remove them from the classpath or use '-Xallow-unstable-dependencies' to suppress errors"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diagnostics.any { it.factory == Errors.FIR_COMPILED_CLASS }) {
|
||||||
|
messageCollector.report(
|
||||||
|
ERROR,
|
||||||
|
"Classes compiled by the new Kotlin compiler frontend were found in dependencies. " +
|
||||||
|
"Remove them from the classpath or use '-Xallow-unstable-dependencies' to suppress errors"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.cli.jvm.compiler
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.LanguageLevelProjectExtension
|
||||||
|
import com.intellij.pom.java.LanguageLevel
|
||||||
|
|
||||||
|
fun Project.setupHighestLanguageLevel() {
|
||||||
|
LanguageLevelProjectExtension.getInstance(this).languageLevel = LanguageLevel.JDK_15_PREVIEW
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.cli.jvm.compiler
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.LanguageLevelProjectExtension
|
||||||
|
import com.intellij.pom.java.LanguageLevel
|
||||||
|
|
||||||
|
fun Project.setupHighestLanguageLevel() {
|
||||||
|
// LanguageLevelProjectExtension.getInstance(this).languageLevel = LanguageLevel.JDK_15_PREVIEW
|
||||||
|
}
|
||||||
@@ -253,7 +253,7 @@ class KotlinCoreEnvironment private constructor(
|
|||||||
updateClasspath(roots.map { JavaSourceRoot(it, null) })
|
updateClasspath(roots.map { JavaSourceRoot(it, null) })
|
||||||
})
|
})
|
||||||
|
|
||||||
LanguageLevelProjectExtension.getInstance(project).languageLevel = LanguageLevel.JDK_15_PREVIEW
|
project.setupHighestLanguageLevel()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectAdditionalSources(project: MockProject) {
|
private fun collectAdditionalSources(project: MockProject) {
|
||||||
|
|||||||
@@ -1,703 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 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.cli.jvm.compiler
|
|
||||||
|
|
||||||
import com.intellij.codeInsight.ExternalAnnotationsManager
|
|
||||||
import com.intellij.codeInsight.InferredAnnotationsManager
|
|
||||||
import com.intellij.core.CoreApplicationEnvironment
|
|
||||||
import com.intellij.core.CoreJavaFileManager
|
|
||||||
import com.intellij.core.JavaCoreProjectEnvironment
|
|
||||||
import com.intellij.ide.highlighter.JavaFileType
|
|
||||||
import com.intellij.lang.java.JavaParserDefinition
|
|
||||||
import com.intellij.mock.MockProject
|
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.application.TransactionGuard
|
|
||||||
import com.intellij.openapi.application.TransactionGuardImpl
|
|
||||||
import com.intellij.openapi.components.ServiceManager
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
|
||||||
import com.intellij.openapi.extensions.Extensions
|
|
||||||
import com.intellij.openapi.extensions.ExtensionsArea
|
|
||||||
import com.intellij.openapi.fileTypes.PlainTextFileType
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.roots.LanguageLevelProjectExtension
|
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import com.intellij.openapi.util.io.FileUtilRt
|
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
|
||||||
import com.intellij.openapi.vfs.*
|
|
||||||
import com.intellij.openapi.vfs.impl.ZipHandler
|
|
||||||
import com.intellij.pom.java.LanguageLevel
|
|
||||||
import com.intellij.psi.PsiElementFinder
|
|
||||||
import com.intellij.psi.PsiManager
|
|
||||||
import com.intellij.psi.compiled.ClassFileDecompilers
|
|
||||||
import com.intellij.psi.impl.JavaClassSupersImpl
|
|
||||||
import com.intellij.psi.impl.PsiElementFinderImpl
|
|
||||||
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
|
||||||
import com.intellij.psi.impl.file.impl.JavaFileManager
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
|
||||||
import com.intellij.psi.util.JavaClassSupers
|
|
||||||
import com.intellij.util.io.URLUtil
|
|
||||||
import com.intellij.util.lang.UrlClassLoader
|
|
||||||
import org.jetbrains.annotations.TestOnly
|
|
||||||
import org.jetbrains.kotlin.asJava.KotlinAsJavaSupport
|
|
||||||
import org.jetbrains.kotlin.asJava.LightClassGenerationSupport
|
|
||||||
import org.jetbrains.kotlin.asJava.classes.FacadeCache
|
|
||||||
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
|
|
||||||
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
|
|
||||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
|
||||||
import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
|
|
||||||
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
|
|
||||||
import org.jetbrains.kotlin.cli.common.config.ContentRoot
|
|
||||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
|
||||||
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
|
|
||||||
import org.jetbrains.kotlin.cli.common.extensions.ScriptEvaluationExtension
|
|
||||||
import org.jetbrains.kotlin.cli.common.extensions.ShellExtension
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
|
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
|
||||||
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.JvmRuntimeVersionsConsistencyChecker
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.*
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.index.*
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.javac.JavacWrapperRegistrar
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleResolver
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
|
||||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
|
||||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
|
||||||
import org.jetbrains.kotlin.config.*
|
|
||||||
import org.jetbrains.kotlin.extensions.*
|
|
||||||
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
|
|
||||||
import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
|
||||||
import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.MetadataFinderFactory
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
|
|
||||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer
|
|
||||||
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
|
|
||||||
import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension
|
|
||||||
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtension
|
|
||||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
|
|
||||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
|
||||||
import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin
|
|
||||||
import org.jetbrains.kotlin.utils.PathUtil
|
|
||||||
import java.io.File
|
|
||||||
import java.nio.file.FileSystems
|
|
||||||
import java.util.zip.ZipFile
|
|
||||||
|
|
||||||
class KotlinCoreEnvironment private constructor(
|
|
||||||
val projectEnvironment: JavaCoreProjectEnvironment,
|
|
||||||
private val initialConfiguration: CompilerConfiguration,
|
|
||||||
configFiles: EnvironmentConfigFiles
|
|
||||||
) {
|
|
||||||
|
|
||||||
class ProjectEnvironment(
|
|
||||||
disposable: Disposable,
|
|
||||||
applicationEnvironment: KotlinCoreApplicationEnvironment
|
|
||||||
) :
|
|
||||||
KotlinCoreProjectEnvironment(disposable, applicationEnvironment) {
|
|
||||||
|
|
||||||
private var extensionRegistered = false
|
|
||||||
|
|
||||||
override fun preregisterServices() {
|
|
||||||
registerProjectExtensionPoints(project.extensionArea)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun registerExtensionsFromPlugins(configuration: CompilerConfiguration) {
|
|
||||||
if (!extensionRegistered) {
|
|
||||||
registerPluginExtensionPoints(project)
|
|
||||||
registerExtensionsFromPlugins(project, configuration)
|
|
||||||
extensionRegistered = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun registerJavaPsiFacade() {
|
|
||||||
with(project) {
|
|
||||||
registerService(
|
|
||||||
CoreJavaFileManager::class.java,
|
|
||||||
ServiceManager.getService(this, JavaFileManager::class.java) as CoreJavaFileManager
|
|
||||||
)
|
|
||||||
|
|
||||||
registerKotlinLightClassSupport(project)
|
|
||||||
|
|
||||||
registerService(ExternalAnnotationsManager::class.java, MockExternalAnnotationsManager())
|
|
||||||
registerService(InferredAnnotationsManager::class.java, MockInferredAnnotationsManager())
|
|
||||||
}
|
|
||||||
|
|
||||||
super.registerJavaPsiFacade()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sourceFiles = mutableListOf<KtFile>()
|
|
||||||
private val rootsIndex: JvmDependenciesDynamicCompoundIndex
|
|
||||||
private val packagePartProviders = mutableListOf<JvmPackagePartProvider>()
|
|
||||||
|
|
||||||
private val classpathRootsResolver: ClasspathRootsResolver
|
|
||||||
private val initialRoots = ArrayList<JavaRoot>()
|
|
||||||
|
|
||||||
val configuration: CompilerConfiguration = initialConfiguration.apply { setupJdkClasspathRoots(configFiles) }.copy()
|
|
||||||
|
|
||||||
init {
|
|
||||||
PersistentFSConstants::class.java.getDeclaredField("ourMaxIntellisenseFileSize")
|
|
||||||
.apply { isAccessible = true }
|
|
||||||
.setInt(null, FileUtilRt.LARGE_FOR_CONTENT_LOADING)
|
|
||||||
|
|
||||||
val project = projectEnvironment.project
|
|
||||||
|
|
||||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
|
||||||
|
|
||||||
(projectEnvironment as? ProjectEnvironment)?.registerExtensionsFromPlugins(configuration)
|
|
||||||
// otherwise consider that project environment is properly configured before passing to the environment
|
|
||||||
// TODO: consider some asserts to check important extension points
|
|
||||||
|
|
||||||
project.registerService(DeclarationProviderFactoryService::class.java, CliDeclarationProviderFactoryService(sourceFiles))
|
|
||||||
|
|
||||||
val isJvm = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES
|
|
||||||
project.registerService(ModuleVisibilityManager::class.java, CliModuleVisibilityManagerImpl(isJvm))
|
|
||||||
|
|
||||||
registerProjectServicesForCLI(projectEnvironment)
|
|
||||||
|
|
||||||
registerProjectServices(projectEnvironment.project)
|
|
||||||
|
|
||||||
for (extension in CompilerConfigurationExtension.getInstances(project)) {
|
|
||||||
extension.updateConfiguration(configuration)
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceFiles += createKtFiles(project)
|
|
||||||
|
|
||||||
collectAdditionalSources(project)
|
|
||||||
|
|
||||||
sourceFiles.sortBy { it.virtualFile.path }
|
|
||||||
|
|
||||||
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
|
|
||||||
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
|
|
||||||
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path ->
|
|
||||||
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
|
|
||||||
})
|
|
||||||
|
|
||||||
val outputDirectory =
|
|
||||||
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
|
|
||||||
?: configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY)?.absolutePath
|
|
||||||
|
|
||||||
classpathRootsResolver = ClasspathRootsResolver(
|
|
||||||
PsiManager.getInstance(project),
|
|
||||||
messageCollector,
|
|
||||||
configuration.getList(JVMConfigurationKeys.ADDITIONAL_JAVA_MODULES),
|
|
||||||
this::contentRootToVirtualFile,
|
|
||||||
javaModuleFinder,
|
|
||||||
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
|
|
||||||
outputDirectory?.let(this::findLocalFile)
|
|
||||||
)
|
|
||||||
|
|
||||||
val (initialRoots, javaModules) =
|
|
||||||
classpathRootsResolver.convertClasspathRoots(configuration.getList(CLIConfigurationKeys.CONTENT_ROOTS))
|
|
||||||
this.initialRoots.addAll(initialRoots)
|
|
||||||
|
|
||||||
if (!configuration.getBoolean(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK) && messageCollector != null) {
|
|
||||||
JvmRuntimeVersionsConsistencyChecker.checkCompilerClasspathConsistency(
|
|
||||||
messageCollector,
|
|
||||||
configuration,
|
|
||||||
initialRoots.mapNotNull { (file, type) -> if (type == JavaRoot.RootType.BINARY) file else null }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val (roots, singleJavaFileRoots) =
|
|
||||||
initialRoots.partition { (file) -> file.isDirectory || file.extension != JavaFileType.DEFAULT_EXTENSION }
|
|
||||||
|
|
||||||
// REPL and kapt2 update classpath dynamically
|
|
||||||
rootsIndex = JvmDependenciesDynamicCompoundIndex().apply {
|
|
||||||
addIndex(JvmDependenciesIndexImpl(roots))
|
|
||||||
updateClasspathFromRootsIndex(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize(
|
|
||||||
rootsIndex,
|
|
||||||
packagePartProviders,
|
|
||||||
SingleJavaFileRootsIndex(singleJavaFileRoots),
|
|
||||||
configuration.getBoolean(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING)
|
|
||||||
)
|
|
||||||
|
|
||||||
project.registerService(
|
|
||||||
JavaModuleResolver::class.java,
|
|
||||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList())
|
|
||||||
)
|
|
||||||
|
|
||||||
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
|
|
||||||
project.registerService(MetadataFinderFactory::class.java, finderFactory)
|
|
||||||
project.registerService(VirtualFileFinderFactory::class.java, finderFactory)
|
|
||||||
|
|
||||||
project.putUserData(APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY, fun(roots: List<File>) {
|
|
||||||
updateClasspath(roots.map { JavaSourceRoot(it, null) })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun collectAdditionalSources(project: MockProject) {
|
|
||||||
var unprocessedSources: Collection<KtFile> = sourceFiles
|
|
||||||
val processedSources = HashSet<KtFile>()
|
|
||||||
val processedSourcesByExtension = HashMap<CollectAdditionalSourcesExtension, Collection<KtFile>>()
|
|
||||||
// repeat feeding extensions with sources while new sources a being added
|
|
||||||
var sourceCollectionIterations = 0
|
|
||||||
while (unprocessedSources.isNotEmpty()) {
|
|
||||||
if (sourceCollectionIterations++ > 10) { // TODO: consider using some appropriate global constant
|
|
||||||
throw IllegalStateException("Unable to collect additional sources in reasonable number of iterations")
|
|
||||||
}
|
|
||||||
processedSources.addAll(unprocessedSources)
|
|
||||||
val allNewSources = ArrayList<KtFile>()
|
|
||||||
for (extension in CollectAdditionalSourcesExtension.getInstances(project)) {
|
|
||||||
// do not feed the extension with the sources it returned on the previous iteration
|
|
||||||
val sourcesToProcess = unprocessedSources - (processedSourcesByExtension[extension] ?: emptyList())
|
|
||||||
val newSources = extension.collectAdditionalSourcesAndUpdateConfiguration(sourcesToProcess, configuration, project)
|
|
||||||
if (newSources.isNotEmpty()) {
|
|
||||||
allNewSources.addAll(newSources)
|
|
||||||
processedSourcesByExtension[extension] = newSources
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unprocessedSources = allNewSources.filterNot { processedSources.contains(it) }.distinct()
|
|
||||||
sourceFiles += unprocessedSources
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addKotlinSourceRoots(rootDirs: List<File>) {
|
|
||||||
val roots = rootDirs.map { KotlinSourceRoot(it.absolutePath, isCommon = false) }
|
|
||||||
sourceFiles += createSourceFilesFromSourceRoots(configuration, project, roots)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider {
|
|
||||||
return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply {
|
|
||||||
addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
|
|
||||||
packagePartProviders += this
|
|
||||||
(ModuleAnnotationsResolver.getInstance(project) as CliModuleAnnotationsResolver).addPackagePartProvider(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val VirtualFile.javaFiles: List<VirtualFile>
|
|
||||||
get() = mutableListOf<VirtualFile>().apply {
|
|
||||||
VfsUtilCore.processFilesRecursively(this@javaFiles) { file ->
|
|
||||||
if (file.fileType == JavaFileType.INSTANCE) {
|
|
||||||
add(file)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val allJavaFiles: List<File>
|
|
||||||
get() = configuration.javaSourceRoots
|
|
||||||
.mapNotNull(this::findLocalFile)
|
|
||||||
.flatMap { it.javaFiles }
|
|
||||||
.map { File(it.canonicalPath) }
|
|
||||||
|
|
||||||
fun registerJavac(
|
|
||||||
javaFiles: List<File> = allJavaFiles,
|
|
||||||
kotlinFiles: List<KtFile> = sourceFiles,
|
|
||||||
arguments: Array<String>? = null,
|
|
||||||
bootClasspath: List<File>? = null,
|
|
||||||
sourcePath: List<File>? = null
|
|
||||||
): Boolean {
|
|
||||||
return JavacWrapperRegistrar.registerJavac(
|
|
||||||
projectEnvironment.project, configuration, javaFiles, kotlinFiles, arguments, bootClasspath, sourcePath,
|
|
||||||
LightClassGenerationSupport.getInstance(project), packagePartProviders
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val applicationEnvironment: CoreApplicationEnvironment
|
|
||||||
get() = projectEnvironment.environment
|
|
||||||
|
|
||||||
val project: Project
|
|
||||||
get() = projectEnvironment.project
|
|
||||||
|
|
||||||
internal fun countLinesOfCode(sourceFiles: List<KtFile>): Int =
|
|
||||||
sourceFiles.sumBy { sourceFile ->
|
|
||||||
val text = sourceFile.text
|
|
||||||
StringUtil.getLineBreakCount(text) + (if (StringUtil.endsWithLineBreak(text)) 0 else 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateClasspathFromRootsIndex(index: JvmDependenciesIndex) {
|
|
||||||
index.indexedRoots.forEach {
|
|
||||||
projectEnvironment.addSourcesToClasspath(it.file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateClasspath(contentRoots: List<ContentRoot>): List<File>? {
|
|
||||||
// TODO: add new Java modules to CliJavaModuleResolver
|
|
||||||
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots
|
|
||||||
|
|
||||||
if (packagePartProviders.isEmpty()) {
|
|
||||||
initialRoots.addAll(newRoots)
|
|
||||||
} else {
|
|
||||||
for (packagePartProvider in packagePartProviders) {
|
|
||||||
packagePartProvider.addRoots(newRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex ->
|
|
||||||
updateClasspathFromRootsIndex(newIndex)
|
|
||||||
newIndex.indexedRoots.mapNotNull { (file) ->
|
|
||||||
VfsUtilCore.virtualToIoFile(VfsUtilCore.getVirtualFileForJar(file) ?: file)
|
|
||||||
}.toList()
|
|
||||||
}.orEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun contentRootToVirtualFile(root: JvmContentRoot): VirtualFile? =
|
|
||||||
when (root) {
|
|
||||||
is JvmClasspathRoot ->
|
|
||||||
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Classpath entry")
|
|
||||||
is JvmModulePathRoot ->
|
|
||||||
if (root.file.isFile) findJarRoot(root.file) else findExistingRoot(root, "Java module root")
|
|
||||||
is JavaSourceRoot ->
|
|
||||||
findExistingRoot(root, "Java source root")
|
|
||||||
else ->
|
|
||||||
throw IllegalStateException("Unexpected root: $root")
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun findLocalFile(path: String): VirtualFile? =
|
|
||||||
applicationEnvironment.localFileSystem.findFileByPath(path)
|
|
||||||
|
|
||||||
private fun findExistingRoot(root: JvmContentRoot, rootDescription: String): VirtualFile? {
|
|
||||||
return findLocalFile(root.file.absolutePath).also {
|
|
||||||
if (it == null) {
|
|
||||||
report(STRONG_WARNING, "$rootDescription points to a non-existent location: ${root.file}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findJarRoot(file: File): VirtualFile? =
|
|
||||||
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
|
|
||||||
|
|
||||||
private fun getSourceRootsCheckingForDuplicates(): List<KotlinSourceRoot> {
|
|
||||||
val uniqueSourceRoots = hashSetOf<String>()
|
|
||||||
val result = mutableListOf<KotlinSourceRoot>()
|
|
||||||
|
|
||||||
for (root in configuration.kotlinSourceRoots) {
|
|
||||||
if (!uniqueSourceRoots.add(root.path)) {
|
|
||||||
report(STRONG_WARNING, "Duplicate source root: ${root.path}")
|
|
||||||
}
|
|
||||||
result.add(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getSourceFiles(): List<KtFile> = sourceFiles
|
|
||||||
|
|
||||||
private fun createKtFiles(project: Project): List<KtFile> =
|
|
||||||
createSourceFilesFromSourceRoots(configuration, project, getSourceRootsCheckingForDuplicates())
|
|
||||||
|
|
||||||
internal fun report(severity: CompilerMessageSeverity, message: String) = configuration.report(severity, message)
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val LOG = Logger.getInstance(KotlinCoreEnvironment::class.java)
|
|
||||||
|
|
||||||
private val APPLICATION_LOCK = Object()
|
|
||||||
private var ourApplicationEnvironment: KotlinCoreApplicationEnvironment? = null
|
|
||||||
private var ourProjectCount = 0
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun createForProduction(
|
|
||||||
parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
|
|
||||||
): KotlinCoreEnvironment {
|
|
||||||
setupIdeaStandaloneExecution()
|
|
||||||
val appEnv = getOrCreateApplicationEnvironmentForProduction(parentDisposable, configuration)
|
|
||||||
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
|
|
||||||
val environment = KotlinCoreEnvironment(projectEnv, configuration, configFiles)
|
|
||||||
|
|
||||||
synchronized(APPLICATION_LOCK) {
|
|
||||||
ourProjectCount++
|
|
||||||
}
|
|
||||||
return environment
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun createForProduction(
|
|
||||||
projectEnvironment: JavaCoreProjectEnvironment, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles
|
|
||||||
): KotlinCoreEnvironment {
|
|
||||||
val environment = KotlinCoreEnvironment(projectEnvironment, configuration, configFiles)
|
|
||||||
|
|
||||||
if (projectEnvironment.environment == applicationEnvironment) {
|
|
||||||
// accounting for core environment disposing
|
|
||||||
synchronized(APPLICATION_LOCK) {
|
|
||||||
ourProjectCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return environment
|
|
||||||
}
|
|
||||||
|
|
||||||
@TestOnly
|
|
||||||
@JvmStatic
|
|
||||||
fun createForTests(
|
|
||||||
parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles
|
|
||||||
): KotlinCoreEnvironment {
|
|
||||||
val configuration = initialConfiguration.copy()
|
|
||||||
// Tests are supposed to create a single project and dispose it right after use
|
|
||||||
val appEnv = createApplicationEnvironment(parentDisposable, configuration, unitTestMode = true)
|
|
||||||
val projectEnv = ProjectEnvironment(parentDisposable, appEnv)
|
|
||||||
return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// used in the daemon for jar cache cleanup
|
|
||||||
val applicationEnvironment: KotlinCoreApplicationEnvironment? get() = ourApplicationEnvironment
|
|
||||||
|
|
||||||
fun getOrCreateApplicationEnvironmentForProduction(
|
|
||||||
parentDisposable: Disposable, configuration: CompilerConfiguration
|
|
||||||
): KotlinCoreApplicationEnvironment {
|
|
||||||
synchronized(APPLICATION_LOCK) {
|
|
||||||
if (ourApplicationEnvironment == null) {
|
|
||||||
val disposable = Disposer.newDisposable()
|
|
||||||
ourApplicationEnvironment = createApplicationEnvironment(disposable, configuration, unitTestMode = false)
|
|
||||||
ourProjectCount = 0
|
|
||||||
Disposer.register(disposable, Disposable {
|
|
||||||
synchronized(APPLICATION_LOCK) {
|
|
||||||
ourApplicationEnvironment = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
if (System.getProperty(KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY).toBooleanLenient() != true) {
|
|
||||||
// JPS may run many instances of the compiler in parallel (there's an option for compiling independent modules in parallel in IntelliJ)
|
|
||||||
// All projects share the same ApplicationEnvironment, and when the last project is disposed, the ApplicationEnvironment is disposed as well
|
|
||||||
@Suppress("ObjectLiteralToLambda") // Disposer tree depends on identity of disposables.
|
|
||||||
Disposer.register(parentDisposable, object : Disposable {
|
|
||||||
override fun dispose() {
|
|
||||||
synchronized(APPLICATION_LOCK) {
|
|
||||||
if (--ourProjectCount <= 0) {
|
|
||||||
disposeApplicationEnvironment()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return ourApplicationEnvironment!!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is also used in Gradle after configuration phase finished.
|
|
||||||
*/
|
|
||||||
fun disposeApplicationEnvironment() {
|
|
||||||
synchronized(APPLICATION_LOCK) {
|
|
||||||
val environment = ourApplicationEnvironment ?: return
|
|
||||||
ourApplicationEnvironment = null
|
|
||||||
Disposer.dispose(environment.parentDisposable)
|
|
||||||
ZipHandler.clearFileAccessorCache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createApplicationEnvironment(
|
|
||||||
parentDisposable: Disposable, configuration: CompilerConfiguration, unitTestMode: Boolean
|
|
||||||
): KotlinCoreApplicationEnvironment {
|
|
||||||
val applicationEnvironment = KotlinCoreApplicationEnvironment.create(parentDisposable, unitTestMode)
|
|
||||||
|
|
||||||
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/compiler.xml")
|
|
||||||
// FIX ME WHEN BUNCH 202 REMOVED: this code is required to support compiler bundled to both 202 and 203.
|
|
||||||
// Please, remove "com.intellij.psi.classFileDecompiler" EP registration once 202 is no longer supported by the compiler
|
|
||||||
if (!Extensions.getRootArea().hasExtensionPoint("com.intellij.psi.classFileDecompiler")) {
|
|
||||||
registerApplicationExtensionPointsAndExtensionsFrom(configuration, "extensions/core.xml")
|
|
||||||
}
|
|
||||||
|
|
||||||
registerApplicationServicesForCLI(applicationEnvironment)
|
|
||||||
registerApplicationServices(applicationEnvironment)
|
|
||||||
|
|
||||||
return applicationEnvironment
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun registerApplicationExtensionPointsAndExtensionsFrom(configuration: CompilerConfiguration, configFilePath: String) {
|
|
||||||
fun File.hasConfigFile(configFile: String): Boolean =
|
|
||||||
if (isDirectory) File(this, "META-INF" + File.separator + configFile).exists()
|
|
||||||
else try {
|
|
||||||
ZipFile(this).use {
|
|
||||||
it.getEntry("META-INF/$configFile") != null
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
val pluginRoot: File =
|
|
||||||
configuration.get(CLIConfigurationKeys.INTELLIJ_PLUGIN_ROOT)?.let(::File)
|
|
||||||
?: PathUtil.getResourcePathForClass(this::class.java).takeIf { it.hasConfigFile(configFilePath) }
|
|
||||||
// hack for load extensions when compiler run directly from project directory (e.g. in tests)
|
|
||||||
?: File("compiler/cli/cli-common/resources").takeIf { it.hasConfigFile(configFilePath) }
|
|
||||||
?: throw IllegalStateException(
|
|
||||||
"Unable to find extension point configuration $configFilePath " +
|
|
||||||
"(cp:\n ${(Thread.currentThread().contextClassLoader as? UrlClassLoader)?.urls?.joinToString("\n ") { it.file }})"
|
|
||||||
)
|
|
||||||
|
|
||||||
CoreApplicationEnvironment.registerExtensionPointAndExtensions(
|
|
||||||
FileSystems.getDefault().getPath(pluginRoot.path),
|
|
||||||
configFilePath,
|
|
||||||
Extensions.getRootArea()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
@Suppress("MemberVisibilityCanPrivate") // made public for CLI Android Lint
|
|
||||||
fun registerPluginExtensionPoints(project: MockProject) {
|
|
||||||
ExpressionCodegenExtension.registerExtensionPoint(project)
|
|
||||||
SyntheticResolveExtension.registerExtensionPoint(project)
|
|
||||||
ClassBuilderInterceptorExtension.registerExtensionPoint(project)
|
|
||||||
AnalysisHandlerExtension.registerExtensionPoint(project)
|
|
||||||
PackageFragmentProviderExtension.registerExtensionPoint(project)
|
|
||||||
StorageComponentContainerContributor.registerExtensionPoint(project)
|
|
||||||
DeclarationAttributeAltererExtension.registerExtensionPoint(project)
|
|
||||||
PreprocessedVirtualFileFactoryExtension.registerExtensionPoint(project)
|
|
||||||
JsSyntheticTranslateExtension.registerExtensionPoint(project)
|
|
||||||
CompilerConfigurationExtension.registerExtensionPoint(project)
|
|
||||||
CollectAdditionalSourcesExtension.registerExtensionPoint(project)
|
|
||||||
ExtraImportsProviderExtension.registerExtensionPoint(project)
|
|
||||||
IrGenerationExtension.registerExtensionPoint(project)
|
|
||||||
ScriptEvaluationExtension.registerExtensionPoint(project)
|
|
||||||
ShellExtension.registerExtensionPoint(project)
|
|
||||||
TypeResolutionInterceptor.registerExtensionPoint(project)
|
|
||||||
CandidateInterceptor.registerExtensionPoint(project)
|
|
||||||
DescriptorSerializerPlugin.registerExtensionPoint(project)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun registerExtensionsFromPlugins(project: MockProject, configuration: CompilerConfiguration) {
|
|
||||||
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
|
||||||
for (registrar in configuration.getList(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS)) {
|
|
||||||
try {
|
|
||||||
registrar.registerProjectComponents(project, configuration)
|
|
||||||
} catch (e: AbstractMethodError) {
|
|
||||||
val message = "The provided plugin ${registrar.javaClass.name} is not compatible with this version of compiler"
|
|
||||||
// Since the scripting plugin is often discovered in the compiler environment, it is often taken from the incompatible
|
|
||||||
// location, and in many cases this is not a fatal error, therefore strong warning is generated instead of exception
|
|
||||||
if (registrar.javaClass.simpleName == "ScriptingCompilerConfigurationComponentRegistrar") {
|
|
||||||
messageCollector?.report(STRONG_WARNING, "Default scripting plugin is disabled: $message")
|
|
||||||
} else {
|
|
||||||
throw IllegalStateException(message, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun registerApplicationServicesForCLI(applicationEnvironment: KotlinCoreApplicationEnvironment) {
|
|
||||||
// ability to get text from annotations xml files
|
|
||||||
applicationEnvironment.registerFileType(PlainTextFileType.INSTANCE, "xml")
|
|
||||||
applicationEnvironment.registerParserDefinition(JavaParserDefinition())
|
|
||||||
}
|
|
||||||
|
|
||||||
// made public for Upsource
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
|
||||||
@JvmStatic
|
|
||||||
fun registerApplicationServices(applicationEnvironment: KotlinCoreApplicationEnvironment) {
|
|
||||||
with(applicationEnvironment) {
|
|
||||||
registerFileType(KotlinFileType.INSTANCE, "kt")
|
|
||||||
registerFileType(KotlinFileType.INSTANCE, KotlinParserDefinition.STD_SCRIPT_SUFFIX)
|
|
||||||
registerParserDefinition(KotlinParserDefinition())
|
|
||||||
application.registerService(KotlinBinaryClassCache::class.java, KotlinBinaryClassCache())
|
|
||||||
application.registerService(JavaClassSupers::class.java, JavaClassSupersImpl::class.java)
|
|
||||||
application.registerService(TransactionGuard::class.java, TransactionGuardImpl::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun registerProjectExtensionPoints(area: ExtensionsArea) {
|
|
||||||
CoreApplicationEnvironment.registerExtensionPoint(
|
|
||||||
area, PsiTreeChangePreprocessor.EP.name, PsiTreeChangePreprocessor::class.java
|
|
||||||
)
|
|
||||||
CoreApplicationEnvironment.registerExtensionPoint(area, PsiElementFinder.EP.name, PsiElementFinder::class.java)
|
|
||||||
|
|
||||||
IdeaExtensionPoints.registerVersionSpecificProjectExtensionPoints(area)
|
|
||||||
}
|
|
||||||
|
|
||||||
// made public for Upsource
|
|
||||||
@JvmStatic
|
|
||||||
@Deprecated("Use registerProjectServices(project) instead.", ReplaceWith("registerProjectServices(projectEnvironment.project)"))
|
|
||||||
fun registerProjectServices(
|
|
||||||
projectEnvironment: JavaCoreProjectEnvironment,
|
|
||||||
@Suppress("UNUSED_PARAMETER") messageCollector: MessageCollector?
|
|
||||||
) {
|
|
||||||
registerProjectServices(projectEnvironment.project)
|
|
||||||
}
|
|
||||||
|
|
||||||
// made public for Android Lint
|
|
||||||
@JvmStatic
|
|
||||||
fun registerProjectServices(project: MockProject) {
|
|
||||||
with(project) {
|
|
||||||
registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this))
|
|
||||||
registerService(FacadeCache::class.java, FacadeCache(this))
|
|
||||||
registerService(ModuleAnnotationsResolver::class.java, CliModuleAnnotationsResolver())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun registerProjectServicesForCLI(@Suppress("UNUSED_PARAMETER") projectEnvironment: JavaCoreProjectEnvironment) {
|
|
||||||
/**
|
|
||||||
* Note that Kapt may restart code analysis process, and CLI services should be aware of that.
|
|
||||||
* Use PsiManager.getModificationTracker() to ensure that all the data you cached is still valid.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// made public for Android Lint
|
|
||||||
@JvmStatic
|
|
||||||
fun registerKotlinLightClassSupport(project: MockProject) {
|
|
||||||
with(project) {
|
|
||||||
val traceHolder = CliTraceHolder()
|
|
||||||
val cliLightClassGenerationSupport = CliLightClassGenerationSupport(traceHolder, project)
|
|
||||||
val kotlinAsJavaSupport = CliKotlinAsJavaSupport(this, traceHolder)
|
|
||||||
registerService(LightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
|
|
||||||
registerService(CliLightClassGenerationSupport::class.java, cliLightClassGenerationSupport)
|
|
||||||
registerService(KotlinAsJavaSupport::class.java, kotlinAsJavaSupport)
|
|
||||||
registerService(CodeAnalyzerInitializer::class.java, traceHolder)
|
|
||||||
|
|
||||||
// We don't pass Disposable because in some tests, we manually unregister these extensions, and that leads to LOG.error
|
|
||||||
// exception from `ExtensionPointImpl.doRegisterExtension`, because the registered extension can no longer be found
|
|
||||||
// when the project is being disposed.
|
|
||||||
// For example, see the `unregisterExtension` call in `GenerationUtils.compileFilesUsingFrontendIR`.
|
|
||||||
// TODO: refactor this to avoid registering unneeded extensions in the first place, and avoid using deprecated API.
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
PsiElementFinder.EP.getPoint(project).registerExtension(JavaElementFinder(this, kotlinAsJavaSupport))
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
PsiElementFinder.EP.getPoint(project).registerExtension(PsiElementFinderImpl(this))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun CompilerConfiguration.setupJdkClasspathRoots(configFiles: EnvironmentConfigFiles) {
|
|
||||||
if (getBoolean(JVMConfigurationKeys.NO_JDK)) return
|
|
||||||
|
|
||||||
val jvmTarget = configFiles == EnvironmentConfigFiles.JVM_CONFIG_FILES
|
|
||||||
if (!jvmTarget) return
|
|
||||||
|
|
||||||
val jdkHome = get(JVMConfigurationKeys.JDK_HOME)
|
|
||||||
val (javaRoot, classesRoots) = if (jdkHome == null) {
|
|
||||||
val javaHome = File(System.getProperty("java.home"))
|
|
||||||
put(JVMConfigurationKeys.JDK_HOME, javaHome)
|
|
||||||
|
|
||||||
javaHome to PathUtil.getJdkClassesRootsFromCurrentJre()
|
|
||||||
} else {
|
|
||||||
jdkHome to PathUtil.getJdkClassesRoots(jdkHome)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!CoreJrtFileSystem.isModularJdk(javaRoot)) {
|
|
||||||
if (classesRoots.isEmpty()) {
|
|
||||||
report(ERROR, "No class roots are found in the JDK path: $javaRoot")
|
|
||||||
} else {
|
|
||||||
addJvmSdkRoots(classesRoots)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+5
-10
@@ -52,10 +52,10 @@ import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback
|
|||||||
import org.jetbrains.kotlin.config.*
|
import org.jetbrains.kotlin.config.*
|
||||||
import org.jetbrains.kotlin.container.get
|
import org.jetbrains.kotlin.container.get
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.diagnostics.*
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
|
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
|
||||||
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
|
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
|
||||||
import org.jetbrains.kotlin.fir.backend.jvm.FirMetadataSerializer
|
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
|
||||||
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
|
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
|
||||||
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
|
||||||
import org.jetbrains.kotlin.fir.session.FirJvmModuleInfo
|
import org.jetbrains.kotlin.fir.session.FirJvmModuleInfo
|
||||||
@@ -389,10 +389,8 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
performanceManager?.notifyIRGenerationStarted()
|
performanceManager?.notifyIRGenerationStarted()
|
||||||
generationState.beforeCompile()
|
generationState.beforeCompile()
|
||||||
codegenFactory.generateModuleInFrontendIRMode(
|
codegenFactory.generateModuleInFrontendIRMode(
|
||||||
generationState, moduleFragment, symbolTable, sourceManager, extensions
|
generationState, moduleFragment, symbolTable, sourceManager, extensions, FirJvmBackendExtension(session, components)
|
||||||
) { context, irClass, _, serializationBindings, parent ->
|
)
|
||||||
FirMetadataSerializer(session, context, irClass, serializationBindings, components, parent)
|
|
||||||
}
|
|
||||||
CodegenFactory.doCheckCancelled(generationState)
|
CodegenFactory.doCheckCancelled(generationState)
|
||||||
generationState.factory.done()
|
generationState.factory.done()
|
||||||
|
|
||||||
@@ -572,8 +570,6 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
sourceFiles: List<KtFile>,
|
sourceFiles: List<KtFile>,
|
||||||
module: Module?
|
module: Module?
|
||||||
): GenerationState {
|
): GenerationState {
|
||||||
val isIR = (configuration.getBoolean(JVMConfigurationKeys.IR) ||
|
|
||||||
configuration.getBoolean(CommonConfigurationKeys.USE_FIR))
|
|
||||||
val generationState = GenerationState.Builder(
|
val generationState = GenerationState.Builder(
|
||||||
environment.project,
|
environment.project,
|
||||||
ClassBuilderFactories.BINARIES,
|
ClassBuilderFactories.BINARIES,
|
||||||
@@ -583,13 +579,12 @@ object KotlinToJVMBytecodeCompiler {
|
|||||||
configuration
|
configuration
|
||||||
)
|
)
|
||||||
.codegenFactory(
|
.codegenFactory(
|
||||||
if (isIR) JvmIrCodegenFactory(
|
if (configuration.getBoolean(JVMConfigurationKeys.IR)) JvmIrCodegenFactory(
|
||||||
configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jvmPhases)
|
configuration.get(CLIConfigurationKeys.PHASE_CONFIG) ?: PhaseConfig(jvmPhases)
|
||||||
) else DefaultCodegenFactory
|
) else DefaultCodegenFactory
|
||||||
)
|
)
|
||||||
.withModule(module)
|
.withModule(module)
|
||||||
.onIndependentPartCompilationEnd(createOutputFilesFlushingCallbackIfPossible(configuration))
|
.onIndependentPartCompilationEnd(createOutputFilesFlushingCallbackIfPossible(configuration))
|
||||||
.isIrBackend(isIR)
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
|||||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||||
import org.jetbrains.kotlin.cli.common.getLibraryFromHome
|
import org.jetbrains.kotlin.cli.common.getLibraryFromHome
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||||
@@ -19,9 +20,6 @@ import org.jetbrains.kotlin.utils.PathUtil
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArguments) {
|
fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArguments) {
|
||||||
|
|
||||||
val messageCollector = getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
|
||||||
|
|
||||||
put(JVMConfigurationKeys.INCLUDE_RUNTIME, arguments.includeRuntime)
|
put(JVMConfigurationKeys.INCLUDE_RUNTIME, arguments.includeRuntime)
|
||||||
|
|
||||||
putIfNotNull(JVMConfigurationKeys.FRIEND_PATHS, arguments.friendPaths?.asList())
|
putIfNotNull(JVMConfigurationKeys.FRIEND_PATHS, arguments.friendPaths?.asList())
|
||||||
@@ -71,9 +69,6 @@ fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArgu
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun CompilerConfiguration.configureJdkHome(arguments: K2JVMCompilerArguments): Boolean {
|
fun CompilerConfiguration.configureJdkHome(arguments: K2JVMCompilerArguments): Boolean {
|
||||||
|
|
||||||
val messageCollector = getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
|
||||||
|
|
||||||
if (arguments.noJdk) {
|
if (arguments.noJdk) {
|
||||||
put(JVMConfigurationKeys.NO_JDK, true)
|
put(JVMConfigurationKeys.NO_JDK, true)
|
||||||
|
|
||||||
@@ -84,7 +79,7 @@ fun CompilerConfiguration.configureJdkHome(arguments: K2JVMCompilerArguments): B
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (arguments.jdkHome != null) {
|
if (arguments.jdkHome != null) {
|
||||||
val jdkHome = File(arguments.jdkHome)
|
val jdkHome = File(arguments.jdkHome!!)
|
||||||
if (!jdkHome.exists()) {
|
if (!jdkHome.exists()) {
|
||||||
messageCollector.report(ERROR, "JDK home directory does not exist: $jdkHome")
|
messageCollector.report(ERROR, "JDK home directory does not exist: $jdkHome")
|
||||||
return false
|
return false
|
||||||
@@ -114,7 +109,6 @@ fun CompilerConfiguration.configureExplicitContentRoots(arguments: K2JVMCompiler
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun CompilerConfiguration.configureStandardLibs(paths: KotlinPaths?, arguments: K2JVMCompilerArguments) {
|
fun CompilerConfiguration.configureStandardLibs(paths: KotlinPaths?, arguments: K2JVMCompilerArguments) {
|
||||||
val messageCollector = getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
|
||||||
val isModularJava = isModularJava()
|
val isModularJava = isModularJava()
|
||||||
|
|
||||||
fun addRoot(moduleName: String, libraryName: String, getLibrary: (KotlinPaths) -> File, noLibraryArgument: String) {
|
fun addRoot(moduleName: String, libraryName: String, getLibrary: (KotlinPaths) -> File, noLibraryArgument: String) {
|
||||||
@@ -171,8 +165,23 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
|
|||||||
|
|
||||||
put(JVMConfigurationKeys.PARAMETERS_METADATA, arguments.javaParameters)
|
put(JVMConfigurationKeys.PARAMETERS_METADATA, arguments.javaParameters)
|
||||||
|
|
||||||
put(JVMConfigurationKeys.IR, arguments.useIR && !arguments.noUseIR)
|
val useIR = (arguments.useIR && !arguments.noUseIR) || arguments.useFir
|
||||||
put(JVMConfigurationKeys.IS_IR_WITH_STABLE_ABI, arguments.isIrWithStableAbi)
|
put(JVMConfigurationKeys.IR, useIR)
|
||||||
|
|
||||||
|
val abiStability = JvmAbiStability.fromStringOrNull(arguments.abiStability)
|
||||||
|
if (arguments.abiStability != null) {
|
||||||
|
if (abiStability == null) {
|
||||||
|
messageCollector.report(
|
||||||
|
ERROR,
|
||||||
|
"Unknown ABI stability mode: ${arguments.abiStability}, supported modes: ${JvmAbiStability.values().map { it.description }}"
|
||||||
|
)
|
||||||
|
} else if (!useIR && abiStability == JvmAbiStability.UNSTABLE) {
|
||||||
|
messageCollector.report(ERROR, "-Xabi-stability=unstable is not supported in the old JVM backend")
|
||||||
|
} else {
|
||||||
|
put(JVMConfigurationKeys.ABI_STABILITY, abiStability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
put(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT, arguments.doNotClearBindingContext)
|
put(JVMConfigurationKeys.DO_NOT_CLEAR_BINDING_CONTEXT, arguments.doNotClearBindingContext)
|
||||||
put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, arguments.noCallAssertions)
|
put(JVMConfigurationKeys.DISABLE_CALL_ASSERTIONS, arguments.noCallAssertions)
|
||||||
put(JVMConfigurationKeys.DISABLE_RECEIVER_ASSERTIONS, arguments.noReceiverAssertions)
|
put(JVMConfigurationKeys.DISABLE_RECEIVER_ASSERTIONS, arguments.noReceiverAssertions)
|
||||||
@@ -189,43 +198,34 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
|
|||||||
put(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS, arguments.noUnifiedNullChecks)
|
put(JVMConfigurationKeys.NO_UNIFIED_NULL_CHECKS, arguments.noUnifiedNullChecks)
|
||||||
|
|
||||||
if (!JVMConstructorCallNormalizationMode.isSupportedValue(arguments.constructorCallNormalizationMode)) {
|
if (!JVMConstructorCallNormalizationMode.isSupportedValue(arguments.constructorCallNormalizationMode)) {
|
||||||
getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
|
messageCollector.report(
|
||||||
ERROR,
|
ERROR,
|
||||||
"Unknown constructor call normalization mode: ${arguments.constructorCallNormalizationMode}, " +
|
"Unknown constructor call normalization mode: ${arguments.constructorCallNormalizationMode}, " +
|
||||||
"supported modes: ${JVMConstructorCallNormalizationMode.values().map { it.description }}"
|
"supported modes: ${JVMConstructorCallNormalizationMode.values().map { it.description }}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val constructorCallNormalizationMode =
|
val constructorCallNormalizationMode = JVMConstructorCallNormalizationMode.fromStringOrNull(arguments.constructorCallNormalizationMode)
|
||||||
JVMConstructorCallNormalizationMode.fromStringOrNull(arguments.constructorCallNormalizationMode)
|
|
||||||
if (constructorCallNormalizationMode != null) {
|
if (constructorCallNormalizationMode != null) {
|
||||||
put(
|
put(JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE, constructorCallNormalizationMode)
|
||||||
JVMConfigurationKeys.CONSTRUCTOR_CALL_NORMALIZATION_MODE,
|
|
||||||
constructorCallNormalizationMode
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val assertionsMode =
|
val assertionsMode =
|
||||||
JVMAssertionsMode.fromStringOrNull(arguments.assertionsMode)
|
JVMAssertionsMode.fromStringOrNull(arguments.assertionsMode)
|
||||||
if (assertionsMode == null) {
|
if (assertionsMode == null) {
|
||||||
getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(
|
messageCollector.report(
|
||||||
ERROR,
|
ERROR,
|
||||||
"Unknown assertions mode: ${arguments.assertionsMode}, " +
|
"Unknown assertions mode: ${arguments.assertionsMode}, supported modes: ${JVMAssertionsMode.values().map { it.description }}"
|
||||||
"supported modes: ${JVMAssertionsMode.values().map { it.description }}"
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
put(
|
put(JVMConfigurationKeys.ASSERTIONS_MODE, assertionsMode ?: JVMAssertionsMode.DEFAULT)
|
||||||
JVMConfigurationKeys.ASSERTIONS_MODE,
|
|
||||||
assertionsMode ?: JVMAssertionsMode.DEFAULT
|
|
||||||
)
|
|
||||||
|
|
||||||
put(JVMConfigurationKeys.USE_TYPE_TABLE, arguments.useTypeTable)
|
put(JVMConfigurationKeys.USE_TYPE_TABLE, arguments.useTypeTable)
|
||||||
put(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK, arguments.skipRuntimeVersionCheck)
|
put(JVMConfigurationKeys.SKIP_RUNTIME_VERSION_CHECK, arguments.skipRuntimeVersionCheck)
|
||||||
put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, arguments.useOldClassFilesReading)
|
put(JVMConfigurationKeys.USE_PSI_CLASS_FILES_READING, arguments.useOldClassFilesReading)
|
||||||
|
|
||||||
if (arguments.useOldClassFilesReading) {
|
if (arguments.useOldClassFilesReading) {
|
||||||
getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
messageCollector.report(INFO, "Using the old java class files reading implementation")
|
||||||
.report(INFO, "Using the old java class files reading implementation")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage)
|
put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, arguments.allowKotlinPackage)
|
||||||
@@ -235,8 +235,7 @@ fun CompilerConfiguration.configureAdvancedJvmOptions(arguments: K2JVMCompilerAr
|
|||||||
put(JVMConfigurationKeys.ENABLE_JVM_PREVIEW, arguments.enableJvmPreview)
|
put(JVMConfigurationKeys.ENABLE_JVM_PREVIEW, arguments.enableJvmPreview)
|
||||||
|
|
||||||
if (arguments.enableJvmPreview) {
|
if (arguments.enableJvmPreview) {
|
||||||
getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
messageCollector.report(INFO, "Using preview Java language features")
|
||||||
.report(INFO, "Using preview Java language features")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
|
arguments.declarationsOutputPath?.let { put(JVMConfigurationKeys.DECLARATIONS_JSON_PATH, it) }
|
||||||
@@ -249,3 +248,6 @@ fun CompilerConfiguration.configureKlibPaths(arguments: K2JVMCompilerArguments)
|
|||||||
?.filterNot { it.isEmpty() }
|
?.filterNot { it.isEmpty() }
|
||||||
?.let { put(JVMConfigurationKeys.KLIB_PATHS, it) }
|
?.let { put(JVMConfigurationKeys.KLIB_PATHS, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val CompilerConfiguration.messageCollector: MessageCollector
|
||||||
|
get() = getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ public class JVMConfigurationKeys {
|
|||||||
public static final CompilerConfigurationKey<List<String>> KLIB_PATHS =
|
public static final CompilerConfigurationKey<List<String>> KLIB_PATHS =
|
||||||
CompilerConfigurationKey.create("Paths to .klib libraries");
|
CompilerConfigurationKey.create("Paths to .klib libraries");
|
||||||
|
|
||||||
public static final CompilerConfigurationKey<Boolean> IS_IR_WITH_STABLE_ABI =
|
public static final CompilerConfigurationKey<JvmAbiStability> ABI_STABILITY =
|
||||||
CompilerConfigurationKey.create("Is IR with stable ABI");
|
CompilerConfigurationKey.create("ABI stability of class files produced by JVM IR and/or FIR");
|
||||||
|
|
||||||
public static final CompilerConfigurationKey<Boolean> DO_NOT_CLEAR_BINDING_CONTEXT =
|
public static final CompilerConfigurationKey<Boolean> DO_NOT_CLEAR_BINDING_CONTEXT =
|
||||||
CompilerConfigurationKey.create("When using the IR backend, do not clear BindingContext between psi2ir and lowerings");
|
CompilerConfigurationKey.create("When using the IR backend, do not clear BindingContext between psi2ir and lowerings");
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.config
|
||||||
|
|
||||||
|
enum class JvmAbiStability(val description: String) {
|
||||||
|
STABLE("stable"),
|
||||||
|
UNSTABLE("unstable"),
|
||||||
|
;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromStringOrNull(string: String?): JvmAbiStability? =
|
||||||
|
values().find { it.description == string }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ object AnalysisFlags {
|
|||||||
val ideMode by AnalysisFlag.Delegates.Boolean
|
val ideMode by AnalysisFlag.Delegates.Boolean
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val reportErrorsOnIrDependencies by AnalysisFlag.Delegates.Boolean
|
val allowUnstableDependencies by AnalysisFlag.Delegates.Boolean
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val libraryToSourceAnalysis by AnalysisFlag.Delegates.Boolean
|
val libraryToSourceAnalysis by AnalysisFlag.Delegates.Boolean
|
||||||
|
|||||||
@@ -14,21 +14,59 @@ dependencies {
|
|||||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
|
||||||
|
|
||||||
testApi(intellijDep())
|
testApi(intellijDep())
|
||||||
|
testApi(projectTests(":compiler:test-infrastructure"))
|
||||||
testApi(commonDep("junit:junit"))
|
testApi(projectTests(":compiler:test-infrastructure-utils"))
|
||||||
testCompileOnly(project(":kotlin-test:kotlin-test-jvm"))
|
testApi(projectTests(":compiler:tests-compiler-utils"))
|
||||||
testCompileOnly(project(":kotlin-test:kotlin-test-junit"))
|
testApi(projectTests(":compiler:tests-common-new"))
|
||||||
testApi(projectTests(":compiler:tests-common"))
|
testApi(project(":compiler:cli"))
|
||||||
testApi(project(":compiler:fir:checkers"))
|
testApi(project(":compiler:fir:checkers"))
|
||||||
testApi(project(":compiler:fir:entrypoint"))
|
testApi(project(":compiler:fir:entrypoint"))
|
||||||
testApi(project(":compiler:frontend"))
|
testApi(project(":compiler:frontend"))
|
||||||
|
|
||||||
testCompileOnly(project(":kotlin-reflect-api"))
|
testApi(platform("org.junit:junit-bom:5.7.0"))
|
||||||
testRuntime(project(":kotlin-reflect"))
|
testApi("org.junit.jupiter:junit-jupiter")
|
||||||
testRuntime(project(":core:descriptors.runtime"))
|
testApi("org.junit.platform:junit-platform-commons:1.7.0")
|
||||||
|
|
||||||
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
testCompileOnly(project(":kotlin-reflect-api"))
|
||||||
testRuntimeOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
testRuntimeOnly(project(":kotlin-reflect"))
|
||||||
|
testRuntimeOnly(project(":core:descriptors.runtime"))
|
||||||
|
|
||||||
|
testImplementation(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
|
testImplementation(intellijDep()) {
|
||||||
|
// This dependency is needed only for FileComparisonFailure
|
||||||
|
includeJars("idea_rt", rootProject = rootProject)
|
||||||
|
isTransitive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is needed only for using FileComparisonFailure, which relies on JUnit 3 classes
|
||||||
|
testRuntimeOnly(commonDep("junit:junit"))
|
||||||
|
testRuntimeOnly(intellijDep()) {
|
||||||
|
includeJars(
|
||||||
|
"jps-model",
|
||||||
|
"extensions",
|
||||||
|
"util",
|
||||||
|
"platform-api",
|
||||||
|
"platform-impl",
|
||||||
|
"idea",
|
||||||
|
"guava",
|
||||||
|
"trove4j",
|
||||||
|
"asm-all",
|
||||||
|
"log4j",
|
||||||
|
"jdom",
|
||||||
|
"streamex",
|
||||||
|
"bootstrap",
|
||||||
|
"jna",
|
||||||
|
rootProject = rootProject
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Platform[202] {
|
||||||
|
testRuntimeOnly(intellijDep()) { includeJars("intellij-deps-fastutil-8.3.1-1") }
|
||||||
|
}
|
||||||
|
Platform[203].orHigher {
|
||||||
|
testRuntimeOnly(intellijDep()) { includeJars("intellij-deps-fastutil-8.3.1-3") }
|
||||||
|
}
|
||||||
|
testRuntimeOnly(toolsJar())
|
||||||
}
|
}
|
||||||
|
|
||||||
val generationRoot = projectDir.resolve("tests-gen")
|
val generationRoot = projectDir.resolve("tests-gen")
|
||||||
@@ -48,11 +86,13 @@ if (kotlinBuildProperties.isInJpsBuildIdeaSync) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
projectTest(parallel = true) {
|
projectTest(parallel = true, jUnit5Enabled = true) {
|
||||||
dependsOn(":dist")
|
dependsOn(":dist")
|
||||||
workingDir = rootDir
|
workingDir = rootDir
|
||||||
jvmArgs!!.removeIf { it.contains("-Xmx") }
|
jvmArgs!!.removeIf { it.contains("-Xmx") }
|
||||||
maxHeapSize = "3g"
|
maxHeapSize = "3g"
|
||||||
|
|
||||||
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
testsJar()
|
testsJar()
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import org.jetbrains.kotlin.ideaExt.idea
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
|
||||||
|
|
||||||
|
testApi(intellijDep())
|
||||||
|
|
||||||
|
testApi(commonDep("junit:junit"))
|
||||||
|
testCompileOnly(project(":kotlin-test:kotlin-test-jvm"))
|
||||||
|
testCompileOnly(project(":kotlin-test:kotlin-test-junit"))
|
||||||
|
testApi(projectTests(":compiler:tests-common"))
|
||||||
|
testApi(project(":compiler:fir:checkers"))
|
||||||
|
testApi(project(":compiler:fir:entrypoint"))
|
||||||
|
testApi(project(":compiler:frontend"))
|
||||||
|
|
||||||
|
testCompileOnly(project(":kotlin-reflect-api"))
|
||||||
|
testRuntimeOnly(project(":kotlin-reflect"))
|
||||||
|
testRuntimeOnly(project(":core:descriptors.runtime"))
|
||||||
|
|
||||||
|
testCompileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
|
testRuntimeOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
|
}
|
||||||
|
|
||||||
|
val generationRoot = projectDir.resolve("tests-gen")
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { none() }
|
||||||
|
"test" {
|
||||||
|
projectDefault()
|
||||||
|
this.java.srcDir(generationRoot.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kotlinBuildProperties.isInJpsBuildIdeaSync) {
|
||||||
|
apply(plugin = "idea")
|
||||||
|
idea {
|
||||||
|
this.module.generatedSourceDirs.add(generationRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest(parallel = true) {
|
||||||
|
dependsOn(":dist")
|
||||||
|
workingDir = rootDir
|
||||||
|
jvmArgs!!.removeIf { it.contains("-Xmx") }
|
||||||
|
maxHeapSize = "3g"
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar()
|
||||||
+413
@@ -1685,6 +1685,419 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class ExtendedCheckers extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInExtendedCheckers() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/extendedCheckers"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ArrayEqualityCanBeReplacedWithEquals.kt")
|
||||||
|
public void testArrayEqualityCanBeReplacedWithEquals() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/ArrayEqualityCanBeReplacedWithEquals.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("CanBeValChecker.kt")
|
||||||
|
public void testCanBeValChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/CanBeValChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantExplicitTypeChecker.kt")
|
||||||
|
public void testRedundantExplicitTypeChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantExplicitTypeChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantModalityModifierChecker.kt")
|
||||||
|
public void testRedundantModalityModifierChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantModalityModifierChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantReturnUnitTypeChecker.kt")
|
||||||
|
public void testRedundantReturnUnitTypeChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantReturnUnitTypeChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantSetterParameterTypeChecker.kt")
|
||||||
|
public void testRedundantSetterParameterTypeChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantSetterParameterTypeChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantSingleExpressionStringTemplateChecker.kt")
|
||||||
|
public void testRedundantSingleExpressionStringTemplateChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantSingleExpressionStringTemplateChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("RedundantVisibilityModifierChecker.kt")
|
||||||
|
public void testRedundantVisibilityModifierChecker() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantVisibilityModifierChecker.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class CanBeReplacedWithOperatorAssignment extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInCanBeReplacedWithOperatorAssignment() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("BasicTest.kt")
|
||||||
|
public void testBasicTest() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/BasicTest.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ComplexExpression.kt")
|
||||||
|
public void testComplexExpression() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/ComplexExpression.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("flexibleTypeBug.kt")
|
||||||
|
public void testFlexibleTypeBug() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/flexibleTypeBug.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("illegalMultipleOperators.kt")
|
||||||
|
public void testIllegalMultipleOperators() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/illegalMultipleOperators.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("illegalMultipleOperatorsMiddle.kt")
|
||||||
|
public void testIllegalMultipleOperatorsMiddle() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/illegalMultipleOperatorsMiddle.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invalidSubtraction.kt")
|
||||||
|
public void testInvalidSubtraction() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/invalidSubtraction.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("list.kt")
|
||||||
|
public void testList() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/list.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("logicOperators.kt")
|
||||||
|
public void testLogicOperators() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/logicOperators.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleOperators.kt")
|
||||||
|
public void testMultipleOperators() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/multipleOperators.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("multipleOperatorsRightSideRepeat.kt")
|
||||||
|
public void testMultipleOperatorsRightSideRepeat() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/multipleOperatorsRightSideRepeat.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("mutableList.kt")
|
||||||
|
public void testMutableList() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/mutableList.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonCommutativeRepeat.kt")
|
||||||
|
public void testNonCommutativeRepeat() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/nonCommutativeRepeat.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nonRepeatingAssignment.kt")
|
||||||
|
public void testNonRepeatingAssignment() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/nonRepeatingAssignment.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("OperatorAssignment.kt")
|
||||||
|
public void testOperatorAssignment() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/OperatorAssignment.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("plusAssignConflict.kt")
|
||||||
|
public void testPlusAssignConflict() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/plusAssignConflict.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("rightSideRepeat.kt")
|
||||||
|
public void testRightSideRepeat() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/rightSideRepeat.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleAssign.kt")
|
||||||
|
public void testSimpleAssign() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/simpleAssign.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("validAddition.kt")
|
||||||
|
public void testValidAddition() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/validAddition.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("validSubtraction.kt")
|
||||||
|
public void testValidSubtraction() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/canBeReplacedWithOperatorAssignment/validSubtraction.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/emptyRangeChecker")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class EmptyRangeChecker extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInEmptyRangeChecker() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/emptyRangeChecker"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NoWarning.kt")
|
||||||
|
public void testNoWarning() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/emptyRangeChecker/NoWarning.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Warning.kt")
|
||||||
|
public void testWarning() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/emptyRangeChecker/Warning.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class RedundantCallOfConversionMethod extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInRedundantCallOfConversionMethod() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("booleanToInt.kt")
|
||||||
|
public void testBooleanToInt() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/booleanToInt.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("byte.kt")
|
||||||
|
public void testByte() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/byte.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("char.kt")
|
||||||
|
public void testChar() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/char.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("double.kt")
|
||||||
|
public void testDouble() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/double.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("float.kt")
|
||||||
|
public void testFloat() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/float.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("int.kt")
|
||||||
|
public void testInt() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/int.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("long.kt")
|
||||||
|
public void testLong() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/long.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullable.kt")
|
||||||
|
public void testNullable() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/nullable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullable2.kt")
|
||||||
|
public void testNullable2() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/nullable2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("safeString.kt")
|
||||||
|
public void testSafeString() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/safeString.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("safeString2.kt")
|
||||||
|
public void testSafeString2() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("short.kt")
|
||||||
|
public void testShort() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/short.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("string.kt")
|
||||||
|
public void testString() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/string.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("StringTemplate.kt")
|
||||||
|
public void testStringTemplate() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/StringTemplate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("toOtherType.kt")
|
||||||
|
public void testToOtherType() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/toOtherType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("uByte.kt")
|
||||||
|
public void testUByte() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/uByte.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("uInt.kt")
|
||||||
|
public void testUInt() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/uInt.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("uLong.kt")
|
||||||
|
public void testULong() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/uLong.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("uShort.kt")
|
||||||
|
public void testUShort() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/uShort.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("variable.kt")
|
||||||
|
public void testVariable() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/RedundantCallOfConversionMethod/variable.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Unused extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInUnused() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("classProperty.kt")
|
||||||
|
public void testClassProperty() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/classProperty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("invoke.kt")
|
||||||
|
public void testInvoke() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/invoke.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambda.kt")
|
||||||
|
public void testLambda() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/lambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localVariable.kt")
|
||||||
|
public void testLocalVariable() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/localVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("manyLocalVariables.kt")
|
||||||
|
public void testManyLocalVariables() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/manyLocalVariables.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("usedInAnnotationArguments.kt")
|
||||||
|
public void testUsedInAnnotationArguments() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/usedInAnnotationArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("valueIsNeverRead.kt")
|
||||||
|
public void testValueIsNeverRead() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/unused/valueIsNeverRead.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class UselessCallOnNotNullChecker extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInUselessCallOnNotNullChecker() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Basic.kt")
|
||||||
|
public void testBasic() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/Basic.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NotNullType.kt")
|
||||||
|
public void testNotNullType() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NotNullType.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NotNullTypeChain.kt")
|
||||||
|
public void testNotNullTypeChain() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NotNullTypeChain.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NullOrBlankSafe.kt")
|
||||||
|
public void testNullOrBlankSafe() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrBlankSafe.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NullOrEmpty.kt")
|
||||||
|
public void testNullOrEmpty() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmpty.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NullOrEmptyFake.kt")
|
||||||
|
public void testNullOrEmptyFake() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmptyFake.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("NullOrEmptySafe.kt")
|
||||||
|
public void testNullOrEmptySafe() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/NullOrEmptySafe.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("OrEmptyFake.kt")
|
||||||
|
public void testOrEmptyFake() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/OrEmptyFake.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SafeCall.kt")
|
||||||
|
public void testSafeCall() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/SafeCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Sequence.kt")
|
||||||
|
public void testSequence() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/Sequence.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("String.kt")
|
||||||
|
public void testString() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/extendedCheckers/UselessCallOnNotNullChecker/String.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/fromBuilder")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/fromBuilder")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
+1
-1
@@ -61,7 +61,7 @@ abstract class AbstractFirTypeEnhancementTest : KtUsefulTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createJarWithForeignAnnotations(): File =
|
private fun createJarWithForeignAnnotations(): File =
|
||||||
MockLibraryUtil.compileJavaFilesLibraryToJar(FOREIGN_ANNOTATIONS_SOURCES_PATH, "foreign-annotations")
|
MockLibraryUtilExt.compileJavaFilesLibraryToJar(FOREIGN_ANNOTATIONS_SOURCES_PATH, "foreign-annotations")
|
||||||
|
|
||||||
private fun createEnvironment(content: String): KotlinCoreEnvironment {
|
private fun createEnvironment(content: String): KotlinCoreEnvironment {
|
||||||
val classpath = mutableListOf(getAnnotationsJar(), ForTestCompileRuntime.runtimeJarForTests())
|
val classpath = mutableListOf(getAnnotationsJar(), ForTestCompileRuntime.runtimeJarForTests())
|
||||||
Vendored
-17
@@ -1,17 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun foo(p: Int) {
|
|
||||||
val a = arrayOf(1, 2, 3)
|
|
||||||
val b = arrayOf(3, 2, 1)
|
|
||||||
|
|
||||||
if (a <!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS!>==<!> b) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testsFromIdea() {
|
|
||||||
val a = arrayOf("a")
|
|
||||||
val b = a
|
|
||||||
val c: Any? = null
|
|
||||||
a <!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS!>==<!> b
|
|
||||||
a == c
|
|
||||||
a <!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS!>!=<!> b
|
|
||||||
}
|
|
||||||
Vendored
-5
@@ -1,5 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
// IS_APPLICABLE: false
|
|
||||||
fun foo(s: String?) {
|
|
||||||
val <!UNUSED_VARIABLE!>t<!>: String = s.toString()
|
|
||||||
}
|
|
||||||
compiler/fir/analysis-tests/testData/extendedCheckers/RedundantCallOfConversionMethod/safeString2.kt
Vendored
-6
@@ -1,6 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
data class Foo(val name: String)
|
|
||||||
|
|
||||||
fun test(foo: Foo?) {
|
|
||||||
val <!UNUSED_VARIABLE!>s<!>: String? = foo?.name?.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toString()<!>
|
|
||||||
}
|
|
||||||
Vendored
-4
@@ -1,4 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
fun test(i: UByte) {
|
|
||||||
val <!UNUSED_VARIABLE!>foo<!> = i.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toUByte()<!>
|
|
||||||
}
|
|
||||||
Vendored
-4
@@ -1,4 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
fun test(i: UInt) {
|
|
||||||
val <!UNUSED_VARIABLE!>foo<!> = i.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toUInt()<!>
|
|
||||||
}
|
|
||||||
Vendored
-4
@@ -1,4 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
fun test(i: ULong) {
|
|
||||||
val <!UNUSED_VARIABLE!>foo<!> = i.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toULong()<!>
|
|
||||||
}
|
|
||||||
Vendored
-4
@@ -1,4 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
fun test(i: UShort) {
|
|
||||||
val <!UNUSED_VARIABLE!>foo<!> = i.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toUShort()<!>
|
|
||||||
}
|
|
||||||
-76
@@ -1,76 +0,0 @@
|
|||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
@Target(AnnotationTarget.TYPE)
|
|
||||||
annotation class A
|
|
||||||
|
|
||||||
fun annotated() {
|
|
||||||
val <!UNUSED_VARIABLE!>x<!>: @A Int /* NOT redundant */ = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
object SomeObj
|
|
||||||
fun fer() {
|
|
||||||
val <!UNUSED_VARIABLE!>x<!>: Any /* NOT redundant */ = SomeObj
|
|
||||||
}
|
|
||||||
|
|
||||||
fun f2(y: String?): String {
|
|
||||||
val <!UNUSED_VARIABLE!>f<!>: KClass<*> = (y ?: return "")::class
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
object Obj {}
|
|
||||||
|
|
||||||
interface IA
|
|
||||||
interface IB : IA
|
|
||||||
|
|
||||||
fun IA.extFun(x: IB) {}
|
|
||||||
|
|
||||||
fun testWithExpectedType() {
|
|
||||||
val <!UNUSED_VARIABLE!>extFun_AB_A<!>: IA.(IB) -> Unit = IA::extFun
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Point {
|
|
||||||
val x: Int
|
|
||||||
val y: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
class PointImpl(override val x: Int, override val y: Int) : Point
|
|
||||||
|
|
||||||
fun foo() {
|
|
||||||
val <!UNUSED_VARIABLE!>s<!>: <!REDUNDANT_EXPLICIT_TYPE!>String<!> = "Hello ${10+1}"
|
|
||||||
val <!UNUSED_VARIABLE!>str<!>: String? = ""
|
|
||||||
|
|
||||||
val <!UNUSED_VARIABLE!>o<!>: <!REDUNDANT_EXPLICIT_TYPE!>Obj<!> = Obj
|
|
||||||
|
|
||||||
val <!UNUSED_VARIABLE!>p<!>: Point = PointImpl(1, 2)
|
|
||||||
val <!UNUSED_VARIABLE!>a<!>: <!REDUNDANT_EXPLICIT_TYPE!>Boolean<!> = true
|
|
||||||
val <!UNUSED_VARIABLE!>i<!>: Int = 2 * 2
|
|
||||||
val <!UNUSED_VARIABLE!>l<!>: <!REDUNDANT_EXPLICIT_TYPE!>Long<!> = 1234567890123L
|
|
||||||
val <!UNUSED_VARIABLE!>s<!>: String? = null
|
|
||||||
val <!UNUSED_VARIABLE!>sh<!>: Short = 42
|
|
||||||
|
|
||||||
val <!UNUSED_VARIABLE!>integer<!>: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 42
|
|
||||||
val <!UNUSED_VARIABLE!>piFloat<!>: <!REDUNDANT_EXPLICIT_TYPE!>Float<!> = 3.14f
|
|
||||||
val <!UNUSED_VARIABLE!>piDouble<!>: <!REDUNDANT_EXPLICIT_TYPE!>Double<!> = 3.14
|
|
||||||
val <!UNUSED_VARIABLE!>charZ<!>: <!REDUNDANT_EXPLICIT_TYPE!>Char<!> = 'z'
|
|
||||||
<!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>alpha<!>: <!REDUNDANT_EXPLICIT_TYPE!>Int<!> = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fun test(boolean: Boolean) {
|
|
||||||
val <!UNUSED_VARIABLE!>expectedLong<!>: Long = if (boolean) {
|
|
||||||
42
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class My {
|
|
||||||
val x: Int = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
val ZERO: Int = 0
|
|
||||||
|
|
||||||
fun main() {
|
|
||||||
val <!UNUSED_VARIABLE!>id<!>: Id = 11
|
|
||||||
}
|
|
||||||
|
|
||||||
typealias Id = Int
|
|
||||||
-85
@@ -1,85 +0,0 @@
|
|||||||
object O {
|
|
||||||
fun foo() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interface
|
|
||||||
interface Interface {
|
|
||||||
// Questionable cuz compiler reports warning here in FE 1.0
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>open<!> val gav: Int
|
|
||||||
get() = 42
|
|
||||||
// Redundant
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun foo()
|
|
||||||
// error
|
|
||||||
private final fun bar() {}
|
|
||||||
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>open<!> fun goo() {}
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun tar()
|
|
||||||
|
|
||||||
// error
|
|
||||||
abstract fun too() {}
|
|
||||||
}
|
|
||||||
interface B {
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> var bar: Unit
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun foo()
|
|
||||||
}
|
|
||||||
interface Foo
|
|
||||||
|
|
||||||
expect abstract class AbstractClass : Foo {
|
|
||||||
abstract override fun foo()
|
|
||||||
|
|
||||||
abstract fun bar()
|
|
||||||
|
|
||||||
abstract val baz: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Abstract
|
|
||||||
abstract class Base {
|
|
||||||
// Redundant final
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>final<!> fun foo() {}
|
|
||||||
// Abstract
|
|
||||||
abstract fun bar()
|
|
||||||
// Open
|
|
||||||
open val gav = 42
|
|
||||||
}
|
|
||||||
|
|
||||||
class FinalDerived : Base() {
|
|
||||||
// Redundant final
|
|
||||||
override <!REDUNDANT_MODALITY_MODIFIER!>final<!> fun bar() {}
|
|
||||||
// Non-final member in final class
|
|
||||||
override open val gav = 13
|
|
||||||
}
|
|
||||||
// Open
|
|
||||||
open class OpenDerived : Base() {
|
|
||||||
// Final
|
|
||||||
override final fun bar() {}
|
|
||||||
// Redundant open
|
|
||||||
override <!REDUNDANT_MODALITY_MODIFIER!>open<!> val gav = 13
|
|
||||||
}
|
|
||||||
// Redundant final
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>final<!> class Final
|
|
||||||
// Derived interface
|
|
||||||
interface Derived : Interface {
|
|
||||||
// Redundant
|
|
||||||
override <!REDUNDANT_MODALITY_MODIFIER!>open<!> fun foo() {}
|
|
||||||
// error
|
|
||||||
final class Nested
|
|
||||||
}
|
|
||||||
// Derived abstract class
|
|
||||||
abstract class AbstractDerived1(override final val gav: Int) : Interface {
|
|
||||||
// Redundant
|
|
||||||
override <!REDUNDANT_MODALITY_MODIFIER!>open<!> fun foo() {}
|
|
||||||
}
|
|
||||||
// Derived abstract class
|
|
||||||
abstract class AbstractDerived2 : Interface {
|
|
||||||
// Final
|
|
||||||
override final fun foo() {}
|
|
||||||
// Redundant
|
|
||||||
override <!REDUNDANT_MODALITY_MODIFIER!>open<!> val gav = 13
|
|
||||||
}
|
|
||||||
// Redundant abstract interface
|
|
||||||
abstract interface AbstractInterface
|
|
||||||
// Redundant final object
|
|
||||||
<!REDUNDANT_MODALITY_MODIFIER!>final<!> object FinalObject
|
|
||||||
// Open interface
|
|
||||||
open interface OpenInterface
|
|
||||||
Vendored
-86
@@ -1,86 +0,0 @@
|
|||||||
fun f() {
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> <!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>baz<!> = 0
|
|
||||||
class LocalClass {
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>internal<!> var foo = 0
|
|
||||||
}
|
|
||||||
LocalClass().foo = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
internal inline fun internal() {
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
|
|
||||||
<!REDECLARATION!>class C {
|
|
||||||
internal val z = object {
|
|
||||||
fun foo() = 13
|
|
||||||
}
|
|
||||||
}<!>
|
|
||||||
|
|
||||||
class Foo2<
|
|
||||||
T1,
|
|
||||||
T2: T1,
|
|
||||||
> {
|
|
||||||
fun <T1,
|
|
||||||
T2, > foo2() {}
|
|
||||||
|
|
||||||
internal inner class B<T,T2,>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!REDECLARATION!><!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class C {
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> val foo: Int = 0
|
|
||||||
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> fun bar() {}
|
|
||||||
|
|
||||||
}<!>
|
|
||||||
|
|
||||||
open class D {
|
|
||||||
protected open fun willRemainProtected() {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun willBecomePublic() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class E : D() {
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>protected<!> override fun willRemainProtected() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public override fun willBecomePublic() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class F <!REDUNDANT_VISIBILITY_MODIFIER!>private<!> constructor(val x: Int) {
|
|
||||||
FIRST(42)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class G constructor(val y: Int) {
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>private<!> constructor(): this(42)
|
|
||||||
|
|
||||||
object H : G()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface I {
|
|
||||||
fun bar()
|
|
||||||
}
|
|
||||||
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> var baz = 0
|
|
||||||
|
|
||||||
open class J {
|
|
||||||
protected val baz = 0
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>protected<!> get() = field * 2
|
|
||||||
var baf = 0
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> get() = 1
|
|
||||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> set(value) {
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf = 0
|
|
||||||
private get() = 42
|
|
||||||
protected set(value) {
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var bar = 0
|
|
||||||
get() = 3.1415926535
|
|
||||||
set(value) {}
|
|
||||||
}
|
|
||||||
Vendored
-5
@@ -1,5 +0,0 @@
|
|||||||
// WITH_RUNTIME
|
|
||||||
|
|
||||||
fun test(s: Sequence<Int>) {
|
|
||||||
val <!UNUSED_VARIABLE!>foo<!> = s.<!USELESS_CALL_ON_NOT_NULL!>orEmpty()<!>
|
|
||||||
}
|
|
||||||
-7
@@ -1,7 +0,0 @@
|
|||||||
fun goo() {
|
|
||||||
var a = 2
|
|
||||||
val b = 4
|
|
||||||
a <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> a + 1 + b
|
|
||||||
a <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> (a + 1)
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = a * b + 1
|
|
||||||
}
|
|
||||||
-5
@@ -1,5 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var x = 0
|
|
||||||
<!CAN_BE_VAL!>var<!> y = 0
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x + y + 5
|
|
||||||
}
|
|
||||||
-5
@@ -1,5 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var x = 0
|
|
||||||
<!CAN_BE_VAL!>var<!> y = 0
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> y + x + 5
|
|
||||||
}
|
|
||||||
-8
@@ -1,8 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var x = 0
|
|
||||||
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x - 1 - 1
|
|
||||||
|
|
||||||
x <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x / 1
|
|
||||||
x = 1 / x
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> -1 + x
|
|
||||||
}
|
|
||||||
-4
@@ -1,4 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var x = 0
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> 1 + x
|
|
||||||
}
|
|
||||||
-5
@@ -1,5 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var y = 0
|
|
||||||
val x = 0
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>y<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> y + x
|
|
||||||
}
|
|
||||||
-4
@@ -1,4 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var x = 0
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x + 1
|
|
||||||
}
|
|
||||||
-4
@@ -1,4 +0,0 @@
|
|||||||
fun foo() {
|
|
||||||
var x = 0
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>x<!> <!CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT!>=<!> x - 1
|
|
||||||
}
|
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun foo(p: Int) {
|
||||||
|
val a = arrayOf(1, 2, 3)
|
||||||
|
val b = arrayOf(3, 2, 1)
|
||||||
|
|
||||||
|
if (<!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS{LT}!>a <!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS{PSI}!>==<!> b<!>) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testsFromIdea() {
|
||||||
|
val a = arrayOf("a")
|
||||||
|
val b = a
|
||||||
|
val c: Any? = null
|
||||||
|
<!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS{LT}!>a <!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS{PSI}!>==<!> b<!>
|
||||||
|
a == c
|
||||||
|
<!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS{LT}!>a <!ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS{PSI}!>!=<!> b<!>
|
||||||
|
}
|
||||||
+20
-20
@@ -4,8 +4,8 @@ import kotlin.reflect.KProperty
|
|||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
fun testDelegator() {
|
fun testDelegator() {
|
||||||
var <!UNUSED_VARIABLE!>x<!>: Boolean by LocalFreezableVar(true)
|
<!UNUSED_VARIABLE{LT}!>var <!UNUSED_VARIABLE{PSI}!>x<!>: Boolean by LocalFreezableVar(true)<!>
|
||||||
var <!UNUSED_VARIABLE!>y<!> by LocalFreezableVar("")
|
<!UNUSED_VARIABLE{LT}!>var <!UNUSED_VARIABLE{PSI}!>y<!> by LocalFreezableVar("")<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
class LocalFreezableVar<T>(private var value: T) {
|
class LocalFreezableVar<T>(private var value: T) {
|
||||||
@@ -23,7 +23,7 @@ operator fun C.plusAssign(a: Any) {}
|
|||||||
fun testOperatorAssignment() {
|
fun testOperatorAssignment() {
|
||||||
val c = C()
|
val c = C()
|
||||||
c += ""
|
c += ""
|
||||||
<!CAN_BE_VAL!>var<!> c1 = C()
|
<!CAN_BE_VAL{LT}!><!CAN_BE_VAL{PSI}!>var<!> c1 = C()<!>
|
||||||
<!ASSIGN_OPERATOR_AMBIGUITY!>c1 += ""<!>
|
<!ASSIGN_OPERATOR_AMBIGUITY!>c1 += ""<!>
|
||||||
|
|
||||||
var a = 1
|
var a = 1
|
||||||
@@ -33,7 +33,7 @@ fun testOperatorAssignment() {
|
|||||||
|
|
||||||
|
|
||||||
fun destructuringDeclaration() {
|
fun destructuringDeclaration() {
|
||||||
<!CAN_BE_VAL!>var<!> (v1, <!UNUSED_VARIABLE!>v2<!>) = getPair()
|
<!CAN_BE_VAL{LT}!><!CAN_BE_VAL{PSI}!>var<!> (v1, <!UNUSED_VARIABLE!>v2<!>) = getPair()<!>
|
||||||
print(v1)
|
print(v1)
|
||||||
|
|
||||||
var (v3, <!VARIABLE_NEVER_READ!>v4<!>) = getPair()
|
var (v3, <!VARIABLE_NEVER_READ!>v4<!>) = getPair()
|
||||||
@@ -49,11 +49,11 @@ fun destructuringDeclaration() {
|
|||||||
|
|
||||||
val (<!UNUSED_VARIABLE!>a<!>, <!UNUSED_VARIABLE!>b<!>, <!UNUSED_VARIABLE!>c<!>) = Triple(1, 1, 1)
|
val (<!UNUSED_VARIABLE!>a<!>, <!UNUSED_VARIABLE!>b<!>, <!UNUSED_VARIABLE!>c<!>) = Triple(1, 1, 1)
|
||||||
|
|
||||||
<!CAN_BE_VAL!>var<!> (<!UNUSED_VARIABLE!>x<!>, <!UNUSED_VARIABLE!>y<!>, <!UNUSED_VARIABLE!>z<!>) = Triple(1, 1, 1)
|
<!CAN_BE_VAL{LT}!><!CAN_BE_VAL{PSI}!>var<!> (<!UNUSED_VARIABLE!>x<!>, <!UNUSED_VARIABLE!>y<!>, <!UNUSED_VARIABLE!>z<!>) = Triple(1, 1, 1)<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stackOverflowBug() {
|
fun stackOverflowBug() {
|
||||||
<!CAN_BE_VAL!>var<!> <!VARIABLE_NEVER_READ!>a<!>: Int
|
<!CAN_BE_VAL{LT}, VARIABLE_NEVER_READ{LT}!><!CAN_BE_VAL{PSI}!>var<!> <!VARIABLE_NEVER_READ{PSI}!>a<!>: Int<!>
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 1
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 1
|
||||||
for (i in 1..10)
|
for (i in 1..10)
|
||||||
print(i)
|
print(i)
|
||||||
@@ -71,8 +71,8 @@ fun smth(flag: Boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun withAnnotation(p: List<Any>) {
|
fun withAnnotation(p: List<Any>) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
<!CAN_BE_VAL{LT}!>@Suppress("UNCHECKED_CAST")
|
||||||
<!CAN_BE_VAL!>var<!> v = p as List<String>
|
<!CAN_BE_VAL{PSI}!>var<!> v = p as List<String><!>
|
||||||
print(v)
|
print(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,9 +86,9 @@ fun getPair(): Pair<Int, String> = Pair(1, "1")
|
|||||||
fun listReceiver(p: List<String>) {}
|
fun listReceiver(p: List<String>) {}
|
||||||
|
|
||||||
fun withInitializer() {
|
fun withInitializer() {
|
||||||
var <!VARIABLE_NEVER_READ!>v1<!> = 1
|
<!VARIABLE_NEVER_READ{LT}!>var <!VARIABLE_NEVER_READ{PSI}!>v1<!> = 1<!>
|
||||||
var v2 = 2
|
var v2 = 2
|
||||||
<!CAN_BE_VAL!>var<!> v3 = 3
|
<!CAN_BE_VAL{LT}!><!CAN_BE_VAL{PSI}!>var<!> v3 = 3<!>
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>v1<!> = 1
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>v1<!> = 1
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>v2<!>++ // todo mark this UNUSED_CHANGED_VALUES
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>v2<!>++ // todo mark this UNUSED_CHANGED_VALUES
|
||||||
print(v3)
|
print(v3)
|
||||||
@@ -102,10 +102,10 @@ fun test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun foo() {
|
fun foo() {
|
||||||
<!CAN_BE_VAL!>var<!> <!VARIABLE_NEVER_READ!>a<!>: Int
|
<!CAN_BE_VAL{LT}, VARIABLE_NEVER_READ{LT}!><!CAN_BE_VAL{PSI}!>var<!> <!VARIABLE_NEVER_READ{PSI}!>a<!>: Int<!>
|
||||||
val bool = true
|
val bool = true
|
||||||
if (bool) <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 4 else <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 42
|
if (bool) <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 4 else <!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 42
|
||||||
val <!UNUSED_VARIABLE!>b<!>: String
|
<!UNUSED_VARIABLE{LT}!>val <!UNUSED_VARIABLE{PSI}!>b<!>: String<!>
|
||||||
|
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>bool<!> = false
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>bool<!> = false
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ fun cycles() {
|
|||||||
a--
|
a--
|
||||||
}
|
}
|
||||||
|
|
||||||
var <!VARIABLE_NEVER_READ!>b<!>: Int
|
<!VARIABLE_NEVER_READ{LT}!>var <!VARIABLE_NEVER_READ{PSI}!>b<!>: Int<!>
|
||||||
while (a < 10) {
|
while (a < 10) {
|
||||||
a++
|
a++
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>b<!> = a
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>b<!> = a
|
||||||
@@ -124,14 +124,14 @@ fun cycles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun assignedTwice(p: Int) {
|
fun assignedTwice(p: Int) {
|
||||||
var <!VARIABLE_NEVER_READ!>v<!>: Int
|
<!VARIABLE_NEVER_READ{LT}!>var <!VARIABLE_NEVER_READ{PSI}!>v<!>: Int<!>
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>v<!> = 0
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>v<!> = 0
|
||||||
if (p > 0) <!ASSIGNED_VALUE_IS_NEVER_READ!>v<!> = 1
|
if (p > 0) <!ASSIGNED_VALUE_IS_NEVER_READ!>v<!> = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun main(args: Array<String?>) {
|
fun main(args: Array<String?>) {
|
||||||
<!CAN_BE_VAL!>var<!> a: String?
|
<!CAN_BE_VAL{LT}!><!CAN_BE_VAL{PSI}!>var<!> a: String?<!>
|
||||||
val <!UNUSED_VARIABLE!>unused<!> = 0
|
<!UNUSED_VARIABLE{LT}!>val <!UNUSED_VARIABLE{PSI}!>unused<!> = 0<!>
|
||||||
|
|
||||||
if (args.size == 1) {
|
if (args.size == 1) {
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = args[0]
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = args[0]
|
||||||
@@ -144,7 +144,7 @@ fun main(args: Array<String?>) {
|
|||||||
fun run(f: () -> Unit) = f()
|
fun run(f: () -> Unit) = f()
|
||||||
|
|
||||||
fun lambda() {
|
fun lambda() {
|
||||||
var <!VARIABLE_NEVER_READ!>a<!>: Int
|
<!VARIABLE_NEVER_READ{LT}!>var <!VARIABLE_NEVER_READ{PSI}!>a<!>: Int<!>
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 10
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 10
|
||||||
|
|
||||||
run {
|
run {
|
||||||
@@ -153,7 +153,7 @@ fun lambda() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun lambdaInitialization() {
|
fun lambdaInitialization() {
|
||||||
<!CAN_BE_VAL!>var<!> <!VARIABLE_NEVER_READ!>a<!>: Int
|
<!CAN_BE_VAL{LT}, VARIABLE_NEVER_READ{LT}!><!CAN_BE_VAL{PSI}!>var<!> <!VARIABLE_NEVER_READ{PSI}!>a<!>: Int<!>
|
||||||
|
|
||||||
run {
|
run {
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 20
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = 20
|
||||||
@@ -161,7 +161,7 @@ fun lambdaInitialization() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun notAssignedWhenNotUsed(p: Int) {
|
fun notAssignedWhenNotUsed(p: Int) {
|
||||||
<!CAN_BE_VAL!>var<!> v: Int
|
<!CAN_BE_VAL{LT}!><!CAN_BE_VAL{PSI}!>var<!> v: Int<!>
|
||||||
if (p > 0) {
|
if (p > 0) {
|
||||||
v = 1
|
v = 1
|
||||||
print(v)
|
print(v)
|
||||||
@@ -180,6 +180,6 @@ class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun withDelegate() {
|
fun withDelegate() {
|
||||||
var <!VARIABLE_NEVER_READ!>s<!>: String by Delegates.notNull()
|
<!VARIABLE_NEVER_READ{LT}!>var <!VARIABLE_NEVER_READ{PSI}!>s<!>: String by Delegates.notNull()<!>
|
||||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>s<!> = ""
|
<!ASSIGNED_VALUE_IS_NEVER_READ!>s<!> = ""
|
||||||
}
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
// IS_APPLICABLE: false
|
||||||
|
fun foo(s: String?) {
|
||||||
|
<!UNUSED_VARIABLE{LT}!>val <!UNUSED_VARIABLE{PSI}!>t<!>: String = s.toString()<!>
|
||||||
|
}
|
||||||
+2
-2
@@ -3,5 +3,5 @@
|
|||||||
data class Foo(val name: String)
|
data class Foo(val name: String)
|
||||||
|
|
||||||
fun nullable2(foo: Foo?) {
|
fun nullable2(foo: Foo?) {
|
||||||
val <!UNUSED_VARIABLE!>s<!>: String = foo?.name.toString()
|
<!UNUSED_VARIABLE{LT}!>val <!UNUSED_VARIABLE{PSI}!>s<!>: String = foo?.name.toString()<!>
|
||||||
}
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
data class Foo(val name: String)
|
||||||
|
|
||||||
|
fun test(foo: Foo?) {
|
||||||
|
<!UNUSED_VARIABLE{LT}!>val <!UNUSED_VARIABLE{PSI}!>s<!>: String? = foo?.name?.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toString()<!><!>
|
||||||
|
}
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
fun test(i: UByte) {
|
||||||
|
<!UNUSED_VARIABLE{LT}!>val <!UNUSED_VARIABLE{PSI}!>foo<!> = i.<!REDUNDANT_CALL_OF_CONVERSION_METHOD!>toUByte()<!><!>
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user