提交 513f7177 编写于 作者: D Denis.Zharkov

Support loading Java records

^KT-43677 In Progress
上级 f25b7672
......@@ -23,19 +23,18 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaElement
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.JavaMember
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaFieldImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
import org.jetbrains.kotlin.resolve.BindingContext.*
import org.jetbrains.kotlin.resolve.BindingContextUtils
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
class LazyResolveBasedCache(resolveSession: ResolveSession) : AbstractJavaResolverCache(resolveSession) {
override fun recordMethod(method: JavaMethod, descriptor: SimpleFunctionDescriptor) {
BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, (method as? JavaMethodImpl)?.psi ?: return, descriptor)
override fun recordMethod(member: JavaMember, descriptor: SimpleFunctionDescriptor) {
BindingContextUtils.recordFunctionDeclarationToDescriptor(trace, (member as? JavaElementImpl<*>)?.psi ?: return, descriptor)
}
override fun recordConstructor(element: JavaElement, descriptor: ConstructorDescriptor) {
......
......@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.name.Name;
@NotNull Kind kind,
@NotNull JavaMethodDescriptor declaration
) {
super(containingDeclaration, original, declaration.getAnnotations(), declaration.getName(), kind, declaration.getSource());
super(containingDeclaration, original, declaration.getAnnotations(), declaration.getName(), kind, declaration.getSource(), false);
this.declaration = declaration;
setParameterNamesStatus(declaration.hasStableParameterNames(), declaration.hasSynthesizedParameterNames());
}
......
......@@ -88,7 +88,8 @@ public class SignaturesPropagationData {
Annotations.Companion.getEMPTY(),
method.getName(),
//TODO: what to do?
SourceElement.NO_SOURCE
SourceElement.NO_SOURCE,
false
);
autoMethodDescriptor.initialize(
null,
......
......@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.incremental.record
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorFactory
import org.jetbrains.kotlin.resolve.DescriptorUtils
......@@ -113,20 +115,37 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
}
private fun syntheticPropertyInClassNotCached(ownerClass: ClassDescriptor, name: Name): SyntheticPropertyHolder {
val forBean = syntheticPropertyHolderForBeanConvention(name, ownerClass)
if (forBean.descriptor != null) return forBean
fun result(descriptor: PropertyDescriptor?, getterNames: List<Name>, setterName: Name? = null): SyntheticPropertyHolder {
if (lookupTracker === LookupTracker.DO_NOTHING) {
return if (descriptor == null) SyntheticPropertyHolder.EMPTY else SyntheticPropertyHolder(descriptor, emptyList())
}
if (!ownerClass.isRecord()) return forBean
val names = ArrayList<Name>(getterNames.size + (setterName?.let { 1 } ?: 0))
val propertyForComponent = syntheticPropertyDescriptorForRecordComponent(name, ownerClass)
names.addAll(getterNames)
names.addIfNotNull(setterName)
return createSyntheticPropertyHolder(propertyForComponent, forBean.lookedNames, name)
}
return SyntheticPropertyHolder(descriptor, names)
private fun createSyntheticPropertyHolder(
descriptor: PropertyDescriptor?,
lookedNames: List<Name>,
additionalName: Name? = null
): SyntheticPropertyHolder {
if (lookupTracker === LookupTracker.DO_NOTHING) {
return if (descriptor == null) SyntheticPropertyHolder.EMPTY else SyntheticPropertyHolder(descriptor, emptyList())
}
val names = ArrayList<Name>(lookedNames.size + (additionalName?.let { 1 } ?: 0))
names.addAll(lookedNames)
names.addIfNotNull(additionalName)
return SyntheticPropertyHolder(descriptor, names)
}
private fun syntheticPropertyHolderForBeanConvention(
name: Name,
ownerClass: ClassDescriptor
): SyntheticPropertyHolder {
if (name.isSpecial) return SyntheticPropertyHolder.EMPTY
val identifier = name.identifier
......@@ -142,7 +161,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
.flatMap { memberScope.getContributedFunctions(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE) }
.singleOrNull {
it.hasJavaOriginInHierarchy() && isGoodGetMethod(it)
} ?: return result(null, possibleGetMethodNames)
} ?: return createSyntheticPropertyHolder(null, possibleGetMethodNames)
val setMethodName = setMethodName(getMethod.name)
......@@ -152,7 +171,25 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
val propertyType = getMethod.returnType!!
val descriptor = MyPropertyDescriptor.create(ownerClass, getMethod.original, setMethod?.original, name, propertyType)
return result(descriptor, possibleGetMethodNames, setMethodName)
return createSyntheticPropertyHolder(descriptor, possibleGetMethodNames, setMethodName)
}
private fun syntheticPropertyDescriptorForRecordComponent(
name: Name,
ownerClass: ClassDescriptor
): PropertyDescriptor? {
val componentLikeMethod =
ownerClass.unsubstitutedMemberScope
.getContributedFunctions(name, NoLookupLocation.FROM_SYNTHETIC_SCOPE)
.singleOrNull(this::isGoodGetMethod) ?: return null
if (componentLikeMethod !is JavaMethodDescriptor || !componentLikeMethod.isForRecordComponent) {
return null
}
val propertyType = componentLikeMethod.returnType!!
return MyPropertyDescriptor.create(ownerClass, componentLikeMethod.original, null, name, propertyType)
}
private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean {
......@@ -249,8 +286,14 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
if (classifier is ClassDescriptor) {
for (descriptor in classifier.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)) {
if (descriptor is FunctionDescriptor) {
val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(descriptor.getName()) ?: continue
addIfNotNull(syntheticPropertyInClass(Pair(classifier, propertyName)).descriptor)
val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(descriptor.getName())
if (propertyName != null) {
addIfNotNull(syntheticPropertyInClass(Pair(classifier, propertyName)).descriptor)
}
if (classifier.isRecord()) {
addIfNotNull(syntheticPropertyInClass(Pair(classifier, descriptor.name)).descriptor)
}
}
}
} else {
......@@ -258,6 +301,9 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
}
}
private fun ClassifierDescriptor.isRecord() =
this is JavaClassDescriptor && isRecord
private fun SmartList<PropertyDescriptor>?.add(property: PropertyDescriptor?): SmartList<PropertyDescriptor>? {
if (property == null) return this
val list = if (this != null) this else SmartList()
......@@ -280,15 +326,15 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
}
private class MyPropertyDescriptor(
containingDeclaration: DeclarationDescriptor,
original: PropertyDescriptor?,
annotations: Annotations,
modality: Modality,
visibility: DescriptorVisibility,
isVar: Boolean,
name: Name,
kind: CallableMemberDescriptor.Kind,
source: SourceElement
containingDeclaration: DeclarationDescriptor,
original: PropertyDescriptor?,
annotations: Annotations,
modality: Modality,
visibility: DescriptorVisibility,
isVar: Boolean,
name: Name,
kind: CallableMemberDescriptor.Kind,
source: SourceElement
) : SyntheticJavaPropertyDescriptor, PropertyDescriptorImpl(
containingDeclaration, original, annotations, modality, visibility, isVar, name, kind, source,
/* lateInit = */ false, /* isConst = */ false, /* isExpect = */ false, /* isActual = */ false, /* isExternal = */ false,
......@@ -374,13 +420,13 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val l
}
override fun createSubstitutedCopy(
newOwner: DeclarationDescriptor,
newModality: Modality,
newVisibility: DescriptorVisibility,
original: PropertyDescriptor?,
kind: CallableMemberDescriptor.Kind,
newName: Name,
source: SourceElement
newOwner: DeclarationDescriptor,
newModality: Modality,
newVisibility: DescriptorVisibility,
original: PropertyDescriptor?,
kind: CallableMemberDescriptor.Kind,
newName: Name,
source: SourceElement
): PropertyDescriptorImpl {
return MyPropertyDescriptor(newOwner, this, annotations, newModality, newVisibility, isVar, newName, kind, this.source).apply {
getMethod = this@MyPropertyDescriptor.getMethod
......
......@@ -24,12 +24,12 @@ import org.jetbrains.kotlin.load.java.components.AbstractJavaResolverCache
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaElement
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.JavaMember
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
class StubJavaResolverCache(resolveSession: ResolveSession) : AbstractJavaResolverCache(resolveSession) {
override fun recordMethod(method: JavaMethod, descriptor: SimpleFunctionDescriptor) {}
override fun recordMethod(member: JavaMember, descriptor: SimpleFunctionDescriptor) {}
override fun recordConstructor(element: JavaElement, descriptor: ConstructorDescriptor) {}
......@@ -37,4 +37,4 @@ class StubJavaResolverCache(resolveSession: ResolveSession) : AbstractJavaResolv
override fun recordClass(javaClass: JavaClass, descriptor: ClassDescriptor) {}
}
\ No newline at end of file
}
......@@ -157,9 +157,12 @@ class MockKotlinClassifier(override val classId: ClassId,
override val isInterface get() = shouldNotBeCalled()
override val isAnnotationType get() = shouldNotBeCalled()
override val isEnum get() = shouldNotBeCalled()
override val isRecord get() = shouldNotBeCalled()
override val methods get() = shouldNotBeCalled()
override val fields get() = shouldNotBeCalled()
override val constructors get() = shouldNotBeCalled()
override val recordComponents get() = shouldNotBeCalled()
override fun hasDefaultConstructor() = shouldNotBeCalled()
override val annotations get() = shouldNotBeCalled()
override val isDeprecatedInJavaDoc get() = shouldNotBeCalled()
......
......@@ -65,6 +65,9 @@ class FakeSymbolBasedClass(
override val isEnum: Boolean get() = false
override val isRecord: Boolean get() = false
override val recordComponents: Collection<JavaRecordComponent> get() = emptyList()
override val lightClassOriginKind: LightClassOriginKind? get() = null
override val methods: Collection<JavaMethod> get() = emptyList()
......
......@@ -133,6 +133,12 @@ class SymbolBasedClass(
.filter { it.kind == ElementKind.CONSTRUCTOR }
.map { SymbolBasedConstructor(it as ExecutableElement, this, javac) }
override val isRecord: Boolean
get() = false
override val recordComponents: Collection<JavaRecordComponent>
get() = emptyList()
override fun hasDefaultConstructor() = false // default constructors are explicit in symbols
override val innerClassNames: Collection<Name>
......
......@@ -114,6 +114,10 @@ class TreeBasedClass(
override val isEnum: Boolean
get() = tree.modifiers.flags and Flags.ENUM.toLong() != 0L
// TODO: Support
override val isRecord: Boolean
get() = false
override val lightClassOriginKind: LightClassOriginKind?
get() = null
......@@ -134,6 +138,9 @@ class TreeBasedClass(
TreeBasedConstructor(constructor as JCTree.JCMethodDecl, compilationUnit, this, javac)
}
override val recordComponents: Collection<JavaRecordComponent>
get() = emptyList()
override fun hasDefaultConstructor() = !isInterface && constructors.isEmpty()
override val innerClassNames: Collection<Name>
......
......@@ -59,6 +59,9 @@ class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass)
override val isEnum: Boolean
get() = psi.isEnum
override val isRecord: Boolean
get() = psi.isRecord
override val outerClass: JavaClassImpl?
get() {
val outer = psi.containingClass
......@@ -100,6 +103,13 @@ class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass)
return constructors(psi.constructors.filter { method -> method.isConstructor })
}
override val recordComponents: Collection<JavaRecordComponent>
get() {
assertNotLightClass()
return psi.recordComponents.convert(::JavaRecordComponentImpl)
}
override fun hasDefaultConstructor() = !isInterface && constructors.isEmpty()
override val isAbstract: Boolean
......
......@@ -24,14 +24,14 @@ import org.jetbrains.kotlin.load.java.NULLABILITY_ANNOTATIONS
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
private inline fun <Psi, Java> Array<Psi>.convert(factory: (Psi) -> Java): List<Java> =
inline fun <Psi, Java> Array<Psi>.convert(factory: (Psi) -> Java): List<Java> =
when (size) {
0 -> emptyList()
1 -> listOf(factory(first()))
else -> map(factory)
}
private fun <Psi, Java> Collection<Psi>.convert(factory: (Psi) -> Java): List<Java> =
fun <Psi, Java> Collection<Psi>.convert(factory: (Psi) -> Java): List<Java> =
when (size) {
0 -> emptyList()
1 -> listOf(factory(first()))
......
/*
* 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.load.java.structure.impl
import com.intellij.psi.PsiRecordComponent
import org.jetbrains.kotlin.load.java.structure.JavaRecordComponent
import org.jetbrains.kotlin.load.java.structure.JavaType
class JavaRecordComponentImpl(psiRecordComponent: PsiRecordComponent) : JavaMemberImpl<PsiRecordComponent>(psiRecordComponent), JavaRecordComponent {
override val type: JavaType
get() = JavaTypeImpl.create(psi.type)
override val isVararg: Boolean
get() = psi.isVarArgs
}
......@@ -47,6 +47,8 @@ class BinaryJavaClass(
override val methods = arrayListOf<JavaMethod>()
override val fields = arrayListOf<JavaField>()
override val constructors = arrayListOf<JavaConstructor>()
override val recordComponents = arrayListOf<JavaRecordComponent>()
override fun hasDefaultConstructor() = false // never: all constructors explicit in bytecode
override val annotationsByFqName by buildLazyValueForMap()
......@@ -63,6 +65,9 @@ class BinaryJavaClass(
override val isInterface get() = isSet(Opcodes.ACC_INTERFACE)
override val isAnnotationType get() = isSet(Opcodes.ACC_ANNOTATION)
override val isEnum get() = isSet(Opcodes.ACC_ENUM)
override val isRecord get() = isSet(Opcodes.ACC_RECORD)
override val lightClassOriginKind: LightClassOriginKind? get() = null
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = false
......@@ -184,6 +189,16 @@ class BinaryJavaClass(
}
}
override fun visitRecordComponent(name: String, descriptor: String, signature: String?): RecordComponentVisitor? {
val type = signatureParser.parseTypeString(StringCharacterIterator(signature ?: descriptor), context)
// TODO: Read isVararg properly
val isVararg = false
recordComponents.add(BinaryJavaRecordComponent(Name.identifier(name), this, type, isVararg))
return null
}
/**
* All the int-like values (including Char/Boolean) come in visitor as Integer instances
*/
......
......@@ -64,6 +64,22 @@ class BinaryJavaValueParameter(
}
}
class BinaryJavaRecordComponent(
override val name: Name,
override val containingClass: JavaClass,
override val type: JavaType,
override val isVararg: Boolean,
) : JavaRecordComponent, BinaryJavaModifierListOwner {
override val annotations: Collection<JavaAnnotation>
get() = emptyList()
override val access: Int
get() = 0
override val annotationsByFqName: Map<FqName?, JavaAnnotation>
get() = emptyMap()
}
fun isNotTopLevelClass(classContent: ByteArray): Boolean {
var isNotTopLevelClass = false
ClassReader(classContent).accept(
......
// FILE: MyRecord.java
public record MyRecord(int x, CharSequence y) {
}
// FILE: main.kt
fun foo(mr: MyRecord) {
MyRecord(1, "")
mr.x()
mr.y()
mr.x
mr.y
}
package
public fun foo(/*0*/ mr: MyRecord): kotlin.Unit
/*record*/ public final class MyRecord : java.lang.Record {
public constructor MyRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
public abstract override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public abstract override /*1*/ /*fake_override*/ fun toString(): kotlin.String
/*record component*/ public open fun x(): kotlin.Int
/*record component*/ public open fun y(): kotlin.CharSequence!
}
package test
public final class GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!> : java.lang.Record {
public constructor GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!>(/*0*/ x: T!, /*1*/ y: E!)
private final val x: T!
private final val y: E!
public open fun x(): T!
public open fun y(): E!
public open fun y(/*0*/ p0: E!): E!
public open fun z(): kotlin.Double
}
package test
/*record*/ public final class GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!> : java.lang.Record {
public constructor GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!>(/*0*/ x: T!, /*1*/ y: E!)
private final val x: T!
private final val y: E!
/*record component*/ public open fun x(): T!
/*record component*/ public open fun y(): E!
public open fun y(/*0*/ p0: E!): E!
public open fun z(): kotlin.Double
}
package test;
public record GenericRecord<T, E>(T x, E y) {
public E y() { return y; }
public E y(E n) { return y; }
public double z() { return 0.0; }
}
package test
/*record*/ public final class GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!> : java.lang.Record {
public constructor GenericRecord</*0*/ T : kotlin.Any!, /*1*/ E : kotlin.Any!>(/*0*/ x: T!, /*1*/ y: E!)
/*record component*/ public open fun x(): T!
/*record component*/ public open fun y(): E!
public open fun y(/*0*/ n: E!): E!
public open fun z(): kotlin.Double
}
package test
public final class SimpleRecord : java.lang.Record {
public constructor SimpleRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
private final val x: kotlin.Int
private final val y: kotlin.CharSequence!
public open fun x(): kotlin.Int
public open fun y(): kotlin.CharSequence!
public open fun y(/*0*/ p0: kotlin.Int): kotlin.CharSequence!
public open fun z(): kotlin.Double
}
package test
/*record*/ public final class SimpleRecord : java.lang.Record {
public constructor SimpleRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
private final val x: kotlin.Int
private final val y: kotlin.CharSequence!
/*record component*/ public open fun x(): kotlin.Int
/*record component*/ public open fun y(): kotlin.CharSequence!
public open fun y(/*0*/ p0: kotlin.Int): kotlin.CharSequence!
public open fun z(): kotlin.Double
}
package test;
public record SimpleRecord(int x, CharSequence y) {
public CharSequence y() { return y; }
public CharSequence y(int n) { return y; }
public double z() { return 0.0; }
}
package test
/*record*/ public final class SimpleRecord : java.lang.Record {
public constructor SimpleRecord(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.CharSequence!)
/*record component*/ public open fun x(): kotlin.Int
/*record component*/ public open fun y(): kotlin.CharSequence!
public open fun y(/*0*/ n: kotlin.Int): kotlin.CharSequence!
public open fun z(): kotlin.Double
}
/*
* 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.checkers
import org.jetbrains.kotlin.test.TestJdkKind
abstract class AbstractDiagnosticsWithJdk15Test : AbstractDiagnosticsTest() {
override fun getTestJdkKind(files: List<TestFile>): TestJdkKind {
return TestJdkKind.FULL_JDK_15
}
}
/*
* 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.jvm.compiler
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
abstract class AbstractLoadJava15Test : AbstractLoadJavaTest() {
override fun getJdkKind(): TestJdkKind = TestJdkKind.FULL_JDK_15
override fun getJdkHomeForJavac(): File = KotlinTestUtils.getJdk15Home()
override fun getAdditionalJavacArgs(): List<String> = ADDITIONAL_JAVAC_ARGS_FOR_15
}
val ADDITIONAL_JAVAC_ARGS_FOR_15 = listOf("--release", "15", "--enable-preview")
\ No newline at end of file
/*
* 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.jvm.compiler
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
import java.io.File
abstract class AbstractLoadJava15WithPsiClassReadingTest : AbstractLoadJavaWithPsiClassReadingTest() {
override fun getJdkKind(): TestJdkKind = TestJdkKind.FULL_JDK_15
override fun getJdkHomeForJavac(): File = KotlinTestUtils.getJdk15Home()
override fun getAdditionalJavacArgs(): List<String> = ADDITIONAL_JAVAC_ARGS_FOR_15
}
......@@ -9,6 +9,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import junit.framework.ComparisonFailure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.analyzer.AnalysisResult;
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettingsKt;
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
......@@ -299,7 +300,19 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
Pair<PackageViewDescriptor, BindingContext> javaPackageAndContext = compileJavaAndLoadTestPackageAndBindingContextFromBinary(
srcFiles, compiledDir, ConfigurationKind.ALL
);
checkJavaPackage(getExpectedFile(javaFileName.replaceFirst("\\.java$", ".txt")), javaPackageAndContext.first, javaPackageAndContext.second, configuration);
checkJavaPackage(getExpectedFile(
useTxtSuffixIfFileExists(javaFileName.replaceFirst("\\.java$", ".txt"), "compiled")
), javaPackageAndContext.first, javaPackageAndContext.second, configuration);
}
public static String useTxtSuffixIfFileExists(String name, String suffix) {
File differentResultFile = KotlinTestUtils.replaceExtension(new File(name), suffix + ".txt");
if (differentResultFile.exists()) return differentResultFile.getPath();
return name;
}
@NotNull
......@@ -308,12 +321,21 @@ public abstract class AbstractLoadJavaTest extends TestCaseWithTmpdir {
@NotNull File outDir,
@NotNull ConfigurationKind configurationKind
) throws IOException {
compileJavaWithAnnotationsJar(javaFiles, outDir);
compileJavaWithAnnotationsJar(javaFiles, outDir, getAdditionalJavacArgs(), getJdkHomeForJavac());
return loadTestPackageAndBindingContextFromJavaRoot(outDir, getTestRootDisposable(), getJdkKind(), configurationKind, true,
usePsiClassFilesReading(), useJavacWrapper(), null,
getExtraClasspath(), this::configureEnvironment);
}
protected List<String> getAdditionalJavacArgs() {
return Collections.emptyList();
}
@Nullable
protected File getJdkHomeForJavac() {
return null;
}
private static void checkJavaPackage(
File txtFile,
PackageViewDescriptor javaPackage,
......
......@@ -142,7 +142,12 @@ public class LoadDescriptorUtil {
return Pair.create(packageView, analysisResult.getBindingContext());
}
public static void compileJavaWithAnnotationsJar(@NotNull Collection<File> javaFiles, @NotNull File outDir) throws IOException {
public static void compileJavaWithAnnotationsJar(
@NotNull Collection<File> javaFiles,
@NotNull File outDir,
@NotNull List<String> additionalArgs,
@Nullable File customJdkHomeForJavac
) throws IOException {
List<String> args = new ArrayList<>(Arrays.asList(
"-sourcepath", "compiler/testData/loadJava/include",
"-d", outDir.getPath())
......@@ -170,7 +175,14 @@ public class LoadDescriptorUtil {
args.add("-classpath");
args.add(classpath.stream().map(File::getPath).collect(Collectors.joining(File.pathSeparator)));
KotlinTestUtils.compileJavaFiles(javaFiles, args);
args.addAll(additionalArgs);
if (customJdkHomeForJavac != null) {
KotlinTestUtils.compileJavaFilesExternally(javaFiles, args, customJdkHomeForJavac);
}
else {
KotlinTestUtils.compileJavaFiles(javaFiles, args);
}
}
@NotNull
......
......@@ -680,6 +680,10 @@ public class KotlinTestUtils {
}
public static boolean compileJavaFilesExternallyWithJava9(@NotNull Collection<File> files, @NotNull List<String> options) {
return compileJavaFilesExternally(files, options, getJdk9Home());
}
public static boolean compileJavaFilesExternally(@NotNull Collection<File> files, @NotNull List<String> options, @NotNull File jdkHome) {
List<String> command = new ArrayList<>();
command.add(new File(jdkHome, "bin/javac").getPath());
command.addAll(options);
......
......@@ -27,6 +27,8 @@ import org.jetbrains.kotlin.contracts.description.*;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SubpackagesScope;
import org.jetbrains.kotlin.jvm.compiler.ExpectedLoadErrorsUtil;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.platform.TargetPlatformKt;
import org.jetbrains.kotlin.renderer.*;
......@@ -193,7 +195,24 @@ public class RecursiveDescriptorComparator {
boolean isPrimaryConstructor = conf.checkPrimaryConstructors &&
descriptor instanceof ConstructorDescriptor && ((ConstructorDescriptor) descriptor).isPrimary();
printer.print(isPrimaryConstructor ? "/*primary*/ " : "", conf.renderer.render(descriptor));
boolean isRecord = descriptor instanceof JavaClassDescriptor && ((JavaClassDescriptor) descriptor).isRecord();
boolean isRecordComponent = descriptor instanceof JavaMethodDescriptor && ((JavaMethodDescriptor) descriptor).isForRecordComponent();
StringBuilder prefix = new StringBuilder();
if (isPrimaryConstructor) {
prefix.append("/*primary*/ ");
}
if (isRecord) {
prefix.append("/*record*/ ");
}
if (isRecordComponent) {
prefix.append("/*record component*/ ");
}
printer.print(prefix.toString(), conf.renderer.render(descriptor));
if (descriptor instanceof FunctionDescriptor && conf.checkFunctionContracts) {
printEffectsIfAny((FunctionDescriptor) descriptor, printer);
......
/*
* 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.checkers;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/diagnostics/testsWithJava15")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class DiagnosticsWithJdk15TestGenerated extends AbstractDiagnosticsWithJdk15Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInTestsWithJava15() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/testsWithJava15"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("simpleRecords.kt")
public void testSimpleRecords() throws Exception {
runTest("compiler/testData/diagnostics/testsWithJava15/simpleRecords.kt");
}
}
......@@ -123,6 +123,10 @@ fun main(args: Array<String>) {
model("diagnostics/testsWithJava9")
}
testClass<AbstractDiagnosticsWithJdk15Test> {
model("diagnostics/testsWithJava15")
}
testClass<AbstractDiagnosticsWithUnsignedTypes> {
model("diagnostics/testsWithUnsignedTypes")
}
......@@ -309,6 +313,15 @@ fun main(args: Array<String>) {
model("loadJava/compiledJava", extension = "java", testMethod = "doTestCompiledJava")
}
testClass<AbstractLoadJava15Test> {
model("loadJava15", extension = "java", testMethod = "doTestCompiledJava", testClassName = "CompiledJava")
model("loadJava15", extension = "java", testMethod = "doTestSourceJava", testClassName = "SourceJava")
}
testClass<AbstractLoadJava15WithPsiClassReadingTest> {
model("loadJava15", extension = "java", testMethod = "doTestCompiledJava")
}
testClass<AbstractCompileJavaAgainstKotlinTest> {
model(
"compileJavaAgainstKotlin",
......
/*
* 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.jvm.compiler;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@RunWith(JUnit3RunnerWithInners.class)
public class LoadJava15TestGenerated extends AbstractLoadJava15Test {
@TestMetadata("compiler/testData/loadJava15")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class CompiledJava extends AbstractLoadJava15Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestCompiledJava, this, testDataFilePath);
}
public void testAllFilesPresentInCompiledJava() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava15"), Pattern.compile("^(.+)\\.java$"), null, true);
}
@TestMetadata("GenericRecord.java")
public void testGenericRecord() throws Exception {
runTest("compiler/testData/loadJava15/GenericRecord.java");
}
@TestMetadata("SimpleRecord.java")
public void testSimpleRecord() throws Exception {
runTest("compiler/testData/loadJava15/SimpleRecord.java");
}
}
@TestMetadata("compiler/testData/loadJava15")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class SourceJava extends AbstractLoadJava15Test {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestSourceJava, this, testDataFilePath);
}
public void testAllFilesPresentInSourceJava() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava15"), Pattern.compile("^(.+)\\.java$"), null, true);
}
@TestMetadata("GenericRecord.java")
public void testGenericRecord() throws Exception {
runTest("compiler/testData/loadJava15/GenericRecord.java");
}
@TestMetadata("SimpleRecord.java")
public void testSimpleRecord() throws Exception {
runTest("compiler/testData/loadJava15/SimpleRecord.java");
}
}
}
/*
* 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.jvm.compiler;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/testData/loadJava15")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class LoadJava15WithPsiClassReadingTestGenerated extends AbstractLoadJava15WithPsiClassReadingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestCompiledJava, this, testDataFilePath);
}
public void testAllFilesPresentInLoadJava15() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/loadJava15"), Pattern.compile("^(.+)\\.java$"), null, true);
}
@TestMetadata("GenericRecord.java")
public void testGenericRecord() throws Exception {
runTest("compiler/testData/loadJava15/GenericRecord.java");
}
@TestMetadata("SimpleRecord.java")
public void testSimpleRecord() throws Exception {
runTest("compiler/testData/loadJava15/SimpleRecord.java");
}
}
......@@ -85,11 +85,13 @@ interface JavaClass : JavaClassifier, JavaTypeParameterListOwner, JavaModifierLi
val isInterface: Boolean
val isAnnotationType: Boolean
val isEnum: Boolean
val isRecord: Boolean
val lightClassOriginKind: LightClassOriginKind?
val methods: Collection<JavaMethod>
val fields: Collection<JavaField>
val constructors: Collection<JavaConstructor>
val recordComponents: Collection<JavaRecordComponent>
fun hasDefaultConstructor(): Boolean
}
......@@ -133,6 +135,11 @@ interface JavaValueParameter : JavaAnnotationOwner {
val isVararg: Boolean
}
interface JavaRecordComponent : JavaMember {
val type: JavaType
val isVararg: Boolean
}
interface JavaTypeParameter : JavaClassifier {
val upperBounds: Collection<JavaClassifierType>
}
......@@ -22,10 +22,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.kotlin.load.java.structure.JavaClass;
import org.jetbrains.kotlin.load.java.structure.JavaElement;
import org.jetbrains.kotlin.load.java.structure.JavaField;
import org.jetbrains.kotlin.load.java.structure.JavaMethod;
import org.jetbrains.kotlin.load.java.structure.*;
import org.jetbrains.kotlin.name.FqName;
public interface JavaResolverCache {
......@@ -37,7 +34,7 @@ public interface JavaResolverCache {
}
@Override
public void recordMethod(@NotNull JavaMethod method, @NotNull SimpleFunctionDescriptor descriptor) {
public void recordMethod(@NotNull JavaMember member, @NotNull SimpleFunctionDescriptor descriptor) {
}
@Override
......@@ -56,7 +53,8 @@ public interface JavaResolverCache {
@Nullable
ClassDescriptor getClassResolvedFromSource(@NotNull FqName fqName);
void recordMethod(@NotNull JavaMethod method, @NotNull SimpleFunctionDescriptor descriptor);
// It's a JavaMethod or JavaRecordComponent
void recordMethod(@NotNull JavaMember member, @NotNull SimpleFunctionDescriptor descriptor);
void recordConstructor(@NotNull JavaElement element, @NotNull ConstructorDescriptor descriptor);
......
......@@ -19,4 +19,5 @@ package org.jetbrains.kotlin.load.java.descriptors;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
public interface JavaClassDescriptor extends ClassDescriptor {
boolean isRecord();
}
......@@ -60,6 +60,7 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
}
private ParameterNamesStatus parameterNamesStatus = null;
private final boolean isForRecordComponent;
protected JavaMethodDescriptor(
@NotNull DeclarationDescriptor containingDeclaration,
......@@ -67,9 +68,11 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
@NotNull Annotations annotations,
@NotNull Name name,
@NotNull Kind kind,
@NotNull SourceElement source
@NotNull SourceElement source,
boolean isForRecordComponent
) {
super(containingDeclaration, original, annotations, name, kind, source);
this.isForRecordComponent = isForRecordComponent;
}
@NotNull
......@@ -77,9 +80,10 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
@NotNull DeclarationDescriptor containingDeclaration,
@NotNull Annotations annotations,
@NotNull Name name,
@NotNull SourceElement source
@NotNull SourceElement source,
boolean isForRecordComponent
) {
return new JavaMethodDescriptor(containingDeclaration, null, annotations, name, Kind.DECLARATION, source);
return new JavaMethodDescriptor(containingDeclaration, null, annotations, name, Kind.DECLARATION, source, isForRecordComponent);
}
@NotNull
......@@ -118,6 +122,10 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
this.parameterNamesStatus = ParameterNamesStatus.get(hasStableParameterNames, hasSynthesizedParameterNames);
}
public boolean isForRecordComponent() {
return isForRecordComponent;
}
@NotNull
@Override
protected JavaMethodDescriptor createSubstitutedCopy(
......@@ -134,7 +142,8 @@ public class JavaMethodDescriptor extends SimpleFunctionDescriptorImpl implement
annotations,
newName != null ? newName : getName(),
kind,
source
source,
isForRecordComponent
);
result.setParameterNamesStatus(hasStableParameterNames(), hasSynthesizedParameterNames());
return result;
......
......@@ -26,12 +26,18 @@ interface DeclaredMemberIndex {
fun findFieldByName(name: Name): JavaField?
fun getFieldNames(): Set<Name>
fun getRecordComponentNames(): Set<Name>
fun findRecordComponentByName(name: Name): JavaRecordComponent?
object Empty : DeclaredMemberIndex {
override fun findMethodsByName(name: Name) = listOf<JavaMethod>()
override fun getMethodNames() = emptySet<Name>()
override fun findFieldByName(name: Name): JavaField? = null
override fun getFieldNames() = emptySet<Name>()
override fun getRecordComponentNames(): Set<Name> = emptySet()
override fun findRecordComponentByName(name: Name): JavaRecordComponent? = null
}
}
......@@ -45,11 +51,15 @@ open class ClassDeclaredMemberIndex(
private val methods = jClass.methods.asSequence().filter(methodFilter).groupBy { m -> m.name }
private val fields = jClass.fields.asSequence().filter(memberFilter).associateBy { m -> m.name }
private val components = jClass.recordComponents.filter(memberFilter).associateBy { it.name }
override fun findMethodsByName(name: Name): Collection<JavaMethod> = methods[name] ?: listOf()
override fun getMethodNames(): Set<Name> = jClass.methods.asSequence().filter(methodFilter).mapTo(mutableSetOf(), JavaMethod::name)
override fun findFieldByName(name: Name): JavaField? = fields[name]
override fun getFieldNames(): Set<Name> = jClass.fields.asSequence().filter(memberFilter).mapTo(mutableSetOf(), JavaField::name)
override fun getRecordComponentNames(): Set<Name> = components.keys
override fun findRecordComponentByName(name: Name): JavaRecordComponent? = components[name]
}
......@@ -84,6 +84,8 @@ class LazyJavaClassDescriptor(
override fun getKind() = kind
override fun getModality() = modality
override fun isRecord(): Boolean = jClass.isRecord
// To workaround a problem with Scala compatibility (KT-9700),
// we consider private visibility of a Java top level class as package private
// Shortly: Scala plugin introduces special kind of "private in package" classes
......
......@@ -39,10 +39,7 @@ import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.childForMethod
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
import org.jetbrains.kotlin.load.java.lazy.types.toAttributes
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.kotlin.computeJvmDescriptor
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
......@@ -79,23 +76,79 @@ class LazyJavaClassMemberScope(
it.memberScope.getFunctionNames()
}.apply {
addAll(declaredMemberIndex().getMethodNames())
addAll(declaredMemberIndex().getRecordComponentNames())
addAll(computeClassNames(kindFilter, nameFilter))
}
internal val constructors = c.storageManager.createLazyValue {
val constructors = jClass.constructors
val result = ArrayList<JavaClassConstructorDescriptor>(constructors.size)
val result = ArrayList<ClassConstructorDescriptor>(constructors.size)
for (constructor in constructors) {
val descriptor = resolveConstructor(constructor)
result.add(descriptor)
}
if (jClass.isRecord) {
val defaultConstructor = createDefaultRecordConstructor()
val jvmDescriptor = defaultConstructor.computeJvmDescriptor(withReturnType = false)
if (result.none { it.computeJvmDescriptor(withReturnType = false) == jvmDescriptor }) {
result.add(defaultConstructor)
c.components.javaResolverCache.recordConstructor(jClass, defaultConstructor)
}
}
c.components.signatureEnhancement.enhanceSignatures(
c,
result.ifEmpty { listOfNotNull(createDefaultConstructor()) }
).toList()
}
private fun createDefaultRecordConstructor(): ClassConstructorDescriptor {
val classDescriptor = ownerDescriptor
val constructorDescriptor = JavaClassConstructorDescriptor.createJavaConstructor(
classDescriptor, Annotations.EMPTY, /* isPrimary = */ true, c.components.sourceElementFactory.source(jClass)
)
val valueParameters = createRecordConstructorParameters(constructorDescriptor)
constructorDescriptor.setHasSynthesizedParameterNames(false)
constructorDescriptor.initialize(valueParameters, getConstructorVisibility(classDescriptor))
constructorDescriptor.setHasStableParameterNames(false)
constructorDescriptor.returnType = classDescriptor.defaultType
return constructorDescriptor
}
private fun createRecordConstructorParameters(constructor: ClassConstructorDescriptorImpl): List<ValueParameterDescriptor> {
val components = jClass.recordComponents
val result = ArrayList<ValueParameterDescriptor>(components.size)
val attr = TypeUsage.COMMON.toAttributes(isForAnnotationParameter = false)
for ((index, component) in components.withIndex()) {
val parameterType = c.typeResolver.transformJavaType(component.type, attr)
val varargElementType =
if (component.isVararg) c.components.module.builtIns.getArrayElementType(parameterType) else null
result.add(
ValueParameterDescriptorImpl(
constructor,
null,
index,
Annotations.EMPTY,
component.name,
parameterType,
/* deeclaresDefaultValue = */false,
/* isCrossinline = */ false,
/* isNoinline = */ false,
varargElementType,
c.components.sourceElementFactory.source(component)
)
)
}
return result
}
override fun JavaMethodDescriptor.isVisibleAsFunction(): Boolean {
if (jClass.isAnnotationType) return false
return isVisibleAsFunctionInCurrentClass(this)
......@@ -439,6 +492,42 @@ class LazyJavaClassMemberScope(
}
}
override fun computeImplicitlyDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
if (jClass.isRecord && declaredMemberIndex().findRecordComponentByName(name) != null && result.none { it.valueParameters.isEmpty() }) {
result.add(resolveRecordComponentToFunctionDescriptor(declaredMemberIndex().findRecordComponentByName(name)!!))
}
}
private fun resolveRecordComponentToFunctionDescriptor(recordComponent: JavaRecordComponent): JavaMethodDescriptor {
val annotations = c.resolveAnnotations(recordComponent)
val functionDescriptorImpl = JavaMethodDescriptor.createJavaMethod(
ownerDescriptor, annotations, recordComponent.name, c.components.sourceElementFactory.source(recordComponent), true
)
val returnTypeAttrs = TypeUsage.COMMON.toAttributes(isForAnnotationParameter = false)
val returnType = c.typeResolver.transformJavaType(recordComponent.type, returnTypeAttrs)
functionDescriptorImpl.initialize(
null,
getDispatchReceiverParameter(),
emptyList(),
emptyList(),
returnType,
// Those functions are generated as open in bytecode
// Actually, it should not be important because the class is final anyway, but leaving them open is convenient for consistency
Modality.convertFromFlags(abstract = false, open = true),
DescriptorVisibilities.PUBLIC,
null,
)
functionDescriptorImpl.setParameterNamesStatus(false, false)
c.components.javaResolverCache.recordMethod(recordComponent, functionDescriptorImpl)
return functionDescriptorImpl
}
override fun computeNonDeclaredProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
if (jClass.isAnnotationType) {
computeAnnotationProperties(name, result)
......
......@@ -82,6 +82,10 @@ abstract class LazyJavaScope(
// Fake overrides, values()/valueOf(), etc.
protected abstract fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name)
// It has a similar semantics to computeNonDeclaredFunctions, but it's being called just once per class
// While computeNonDeclaredFunctions is being called once per scope instance (once per KotlinTypeRefiner)
protected open fun computeImplicitlyDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {}
protected abstract fun getDispatchReceiverParameter(): ReceiverParameterDescriptor?
private val declaredFunctions: MemoizedFunctionToNotNull<Name, Collection<SimpleFunctionDescriptor>> =
......@@ -98,6 +102,8 @@ abstract class LazyJavaScope(
result.add(descriptor)
}
computeImplicitlyDeclaredFunctions(result, name)
result
}
......@@ -154,7 +160,8 @@ abstract class LazyJavaScope(
protected fun resolveMethodToFunctionDescriptor(method: JavaMethod): JavaMethodDescriptor {
val annotations = c.resolveAnnotations(method)
val functionDescriptorImpl = JavaMethodDescriptor.createJavaMethod(
ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method)
ownerDescriptor, annotations, method.name, c.components.sourceElementFactory.source(method),
declaredMemberIndex().findRecordComponentByName(method.name) != null && method.valueParameters.isEmpty()
)
val c = c.childForMethod(functionDescriptorImpl, method)
......
......@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.descriptors.runtime.structure
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
import org.jetbrains.kotlin.load.java.structure.JavaRecordComponent
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
......@@ -96,6 +97,9 @@ class ReflectJavaClass(
.map(::ReflectJavaConstructor)
.toList()
override val recordComponents: Collection<JavaRecordComponent>
get() = emptyList()
override fun hasDefaultConstructor() = false // any default constructor is returned by constructors
override val lightClassOriginKind: LightClassOriginKind?
......@@ -114,6 +118,10 @@ class ReflectJavaClass(
override val isEnum: Boolean
get() = klass.isEnum
// TODO: Support reflect
override val isRecord: Boolean
get() = false
override fun equals(other: Any?) = other is ReflectJavaClass && klass == other.klass
override fun hashCode() = klass.hashCode()
......
......@@ -125,7 +125,7 @@ abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdir() {
},
""
)
LoadDescriptorUtil.compileJavaWithAnnotationsJar(sources, tmpdir)
LoadDescriptorUtil.compileJavaWithAnnotationsJar(sources, tmpdir, emptyList(), null)
}
fileName.endsWith(".kt") -> {
val environment = KotlinTestUtils.createEnvironmentWithJdkAndNullabilityAnnotationsFromIdea(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册