Resolve "componentN" functions for data classes
Reuse existing (but not used) VALUE_PARAMETER_AS_PROPERTY in BindingContext to store mapping from constructor's value parameters to property descriptors. Create a new slice DATA_CLASS_COMPONENT_FUNCTION to store mapping from constructor's value parameters to generated componentN functions.
This commit is contained in:
@@ -220,8 +220,11 @@ public interface BindingContext {
|
||||
.setFurtherLookupSlices(DECLARATIONS_TO_DESCRIPTORS).build();
|
||||
|
||||
WritableSlice<JetReferenceExpression, PsiElement> LABEL_TARGET = Slices.<JetReferenceExpression, PsiElement>sliceBuilder().build();
|
||||
WritableSlice<JetParameter, PropertyDescriptor> VALUE_PARAMETER_AS_PROPERTY =
|
||||
Slices.<JetParameter, PropertyDescriptor>sliceBuilder().build();
|
||||
WritableSlice<ValueParameterDescriptor, PropertyDescriptor> VALUE_PARAMETER_AS_PROPERTY =
|
||||
Slices.<ValueParameterDescriptor, PropertyDescriptor>sliceBuilder().build();
|
||||
|
||||
WritableSlice<ValueParameterDescriptor, FunctionDescriptor> DATA_CLASS_COMPONENT_FUNCTION =
|
||||
Slices.<ValueParameterDescriptor, FunctionDescriptor>sliceBuilder().build();
|
||||
|
||||
WritableSlice<FqName, ClassDescriptor> FQNAME_TO_CLASS_DESCRIPTOR = new BasicWritableSlice<FqName, ClassDescriptor>(DO_NOTHING, true);
|
||||
WritableSlice<FqName, NamespaceDescriptor> FQNAME_TO_NAMESPACE_DESCRIPTOR =
|
||||
|
||||
@@ -28,6 +28,8 @@ import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.lang.types.lang.JetStandardLibrary;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.*;
|
||||
@@ -88,6 +90,7 @@ public class DeclarationResolver {
|
||||
resolveConstructorHeaders();
|
||||
resolveAnnotationStubsOnClassesAndConstructors();
|
||||
resolveFunctionAndPropertyHeaders();
|
||||
createComponentFunctionsForDataClasses();
|
||||
importsResolver.processMembersImports(rootScope);
|
||||
checkRedeclarationsInNamespaces();
|
||||
checkRedeclarationsInInnerClassNames();
|
||||
@@ -210,6 +213,38 @@ public class DeclarationResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private void createComponentFunctionsForDataClasses() {
|
||||
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
|
||||
JetClass jetClass = entry.getKey();
|
||||
MutableClassDescriptor classDescriptor = entry.getValue();
|
||||
|
||||
if (jetClass.hasPrimaryConstructor() && JetStandardLibrary.isData(classDescriptor)) {
|
||||
createComponentFunctions(classDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createComponentFunctions(MutableClassDescriptor classDescriptor) {
|
||||
Set<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
|
||||
assert constructors.size() == 1 : "Data class hasn't a single constructor: " + constructors.size();
|
||||
ConstructorDescriptor constructor = constructors.iterator().next();
|
||||
|
||||
int parameterIndex = 0;
|
||||
for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
|
||||
if (!ErrorUtils.isErrorType(parameter.getType())) {
|
||||
PropertyDescriptor property = trace.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter);
|
||||
if (property != null) {
|
||||
++parameterIndex;
|
||||
|
||||
SimpleFunctionDescriptor functionDescriptor =
|
||||
DescriptorResolver.createComponentFunctionDescriptor(parameterIndex, property, parameter, classDescriptor, trace);
|
||||
|
||||
classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) {
|
||||
if (classDescriptor.getKind() == ClassKind.TRAIT) {
|
||||
JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
|
||||
|
||||
@@ -58,6 +58,7 @@ import static org.jetbrains.jet.lexer.JetTokens.OVERRIDE_KEYWORD;
|
||||
public class DescriptorResolver {
|
||||
public static final Name VALUE_OF_METHOD_NAME = Name.identifier("valueOf");
|
||||
public static final Name VALUES_METHOD_NAME = Name.identifier("values");
|
||||
public static final String COMPONENT_FUNCTION_NAME_PREFIX = "component";
|
||||
|
||||
@NotNull
|
||||
private TypeResolver typeResolver;
|
||||
@@ -295,6 +296,40 @@ public class DescriptorResolver {
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static SimpleFunctionDescriptor createComponentFunctionDescriptor(
|
||||
int parameterIndex,
|
||||
@NotNull PropertyDescriptor property,
|
||||
@NotNull ValueParameterDescriptor parameter,
|
||||
@NotNull ClassDescriptor classDescriptor,
|
||||
@NotNull BindingTrace trace
|
||||
) {
|
||||
String functionName = COMPONENT_FUNCTION_NAME_PREFIX + parameterIndex;
|
||||
JetType returnType = property.getType();
|
||||
|
||||
SimpleFunctionDescriptorImpl functionDescriptor = new SimpleFunctionDescriptorImpl(
|
||||
classDescriptor,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
Name.identifier(functionName),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||
);
|
||||
|
||||
functionDescriptor.initialize(
|
||||
null,
|
||||
classDescriptor.getImplicitReceiver(),
|
||||
Collections.<TypeParameterDescriptor>emptyList(),
|
||||
Collections.<ValueParameterDescriptor>emptyList(),
|
||||
returnType,
|
||||
Modality.FINAL,
|
||||
property.getVisibility(),
|
||||
true
|
||||
);
|
||||
|
||||
trace.record(BindingContext.DATA_CLASS_COMPONENT_FUNCTION, parameter, functionDescriptor);
|
||||
|
||||
return functionDescriptor;
|
||||
}
|
||||
|
||||
public static Visibility getDefaultVisibility(JetModifierListOwner modifierListOwner, DeclarationDescriptor containingDescriptor) {
|
||||
Visibility defaultVisibility;
|
||||
if (containingDescriptor instanceof ClassDescriptor) {
|
||||
@@ -1076,6 +1111,7 @@ public class DescriptorResolver {
|
||||
getter.initialize(propertyDescriptor.getType());
|
||||
|
||||
trace.record(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter, propertyDescriptor);
|
||||
trace.record(BindingContext.VALUE_PARAMETER_AS_PROPERTY, valueParameter, propertyDescriptor);
|
||||
return propertyDescriptor;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -277,7 +277,7 @@ public class ExpressionTypingUtils {
|
||||
) {
|
||||
int componentIndex = 1;
|
||||
for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
|
||||
final Name componentName = Name.identifier("component" + componentIndex);
|
||||
final Name componentName = Name.identifier(DescriptorResolver.COMPONENT_FUNCTION_NAME_PREFIX + componentIndex);
|
||||
componentIndex++;
|
||||
|
||||
JetType expectedType = getExpectedTypeForComponent(context, entry);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(x: Int, y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.<!UNRESOLVED_REFERENCE!>component1<!>()
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
open data class A(private val x: Int)
|
||||
|
||||
class B : A(1) {
|
||||
fun component1(): String = ""
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
val b = B()
|
||||
b.component1() : String
|
||||
(b : A).<!INVISIBLE_MEMBER!>component1<!>() : Int
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
open data class A(private val x: Int, protected val y: String, public val z: Any)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.<!INVISIBLE_MEMBER!>component1<!>()
|
||||
a.<!INVISIBLE_MEMBER!>component2<!>()
|
||||
a.component3()
|
||||
}
|
||||
|
||||
class B : A(42, "", "") {
|
||||
fun foo() {
|
||||
this.<!INVISIBLE_MEMBER!>component1<!>()
|
||||
this.component2()
|
||||
this.component3()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
open data class A(val x: Int, val y: String)
|
||||
|
||||
class B : A(42, "OK") {
|
||||
<!OVERRIDING_FINAL_MEMBER!>override<!> fun component1(): Int = 21
|
||||
<!OVERRIDING_FINAL_MEMBER!>override<!> fun component2(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Int<!> = 21
|
||||
}
|
||||
|
||||
fun foo(b: B) {
|
||||
b.component1()
|
||||
b.component2()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(val component1: Int)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1()
|
||||
a.component1
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A()
|
||||
|
||||
fun foo(a: A) {
|
||||
a.<!UNRESOLVED_REFERENCE!>component1<!>()
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(val x: Int, y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : Int
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(var x: Int, y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : Int
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
data class A(val x: Int, val y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
val (b, c) = a
|
||||
b : Int
|
||||
c : String
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
data class A(val x: Int, val y: String)
|
||||
|
||||
fun foo(arr: Array<A>) {
|
||||
for ((b, c) in arr) {
|
||||
b : Int
|
||||
c : String
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class A(val x: Int, val y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.<!UNRESOLVED_REFERENCE!>component1<!>()
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(val x: Int)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : Int
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(x: Int, val y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : String
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(x: Int, var y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : String
|
||||
a.<!UNRESOLVED_REFERENCE!>component2<!>()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(val x: Int, val y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : Int
|
||||
a.component2() : String
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
data class A(var x: Int, var y: String)
|
||||
|
||||
fun foo(a: A) {
|
||||
a.component1() : Int
|
||||
a.component2() : String
|
||||
}
|
||||
@@ -27,7 +27,7 @@ import java.io.File;
|
||||
@InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class})
|
||||
public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
@TestMetadata("compiler/testData/diagnostics/tests")
|
||||
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Enum.class, Tests.Extensions.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Scopes.class, Tests.Shadowing.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Tuples.class, Tests.Varargs.class})
|
||||
@InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.Enum.class, Tests.Extensions.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Scopes.class, Tests.Shadowing.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Tuples.class, Tests.Varargs.class})
|
||||
public static class Tests extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
@TestMetadata("Abstract.kt")
|
||||
public void testAbstract() throws Exception {
|
||||
@@ -946,6 +946,94 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/dataClasses")
|
||||
public static class DataClasses extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInDataClasses() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve", new File("compiler/testData/diagnostics/tests/dataClasses"), "kt", true);
|
||||
}
|
||||
|
||||
@TestMetadata("bothParamsAreNotProperties.kt")
|
||||
public void testBothParamsAreNotProperties() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/bothParamsAreNotProperties.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("componentFunctionInSubClass.kt")
|
||||
public void testComponentFunctionInSubClass() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/componentFunctionInSubClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("componentFunctionVisibility.kt")
|
||||
public void testComponentFunctionVisibility() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/componentFunctionVisibility.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("componentFunctionsAreFinal.kt")
|
||||
public void testComponentFunctionsAreFinal() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/componentFunctionsAreFinal.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("componentNamedComponent1.kt")
|
||||
public void testComponentNamedComponent1() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/componentNamedComponent1.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("emptyConstructor.kt")
|
||||
public void testEmptyConstructor() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/emptyConstructor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("firstParamIsVal.kt")
|
||||
public void testFirstParamIsVal() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/firstParamIsVal.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("firstParamIsVar.kt")
|
||||
public void testFirstParamIsVar() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/firstParamIsVar.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclaration.kt")
|
||||
public void testMultiDeclaration() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/multiDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("multiDeclarationFor.kt")
|
||||
public void testMultiDeclarationFor() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/multiDeclarationFor.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notADataClass.kt")
|
||||
public void testNotADataClass() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/notADataClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("oneValParam.kt")
|
||||
public void testOneValParam() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/oneValParam.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("secondParamIsVal.kt")
|
||||
public void testSecondParamIsVal() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/secondParamIsVal.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("secondParamIsVar.kt")
|
||||
public void testSecondParamIsVar() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/secondParamIsVar.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("twoValParams.kt")
|
||||
public void testTwoValParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/twoValParams.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("twoVarParams.kt")
|
||||
public void testTwoVarParams() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/dataClasses/twoVarParams.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/dataFlow")
|
||||
public static class DataFlow extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInDataFlow() throws Exception {
|
||||
@@ -3189,6 +3277,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
suite.addTestSuite(CheckArguments.class);
|
||||
suite.addTestSuite(ControlFlowAnalysis.class);
|
||||
suite.addTestSuite(ControlStructures.class);
|
||||
suite.addTestSuite(DataClasses.class);
|
||||
suite.addTestSuite(DataFlow.class);
|
||||
suite.addTestSuite(DataFlowInfoTraversal.class);
|
||||
suite.addTest(DeclarationChecks.innerSuite());
|
||||
|
||||
Reference in New Issue
Block a user