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:
Alexander Udalov
2012-08-28 20:05:32 +04:00
parent 410922c58d
commit b93db69a24
21 changed files with 285 additions and 4 deletions
@@ -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;
}
@@ -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());