Generate copy function for data classes

#KT-2779 Fixed
This commit is contained in:
Natalia.Ukhorskaya
2012-10-31 15:34:46 +04:00
parent 6009038342
commit 3b58eb4b60
20 changed files with 388 additions and 33 deletions
@@ -238,6 +238,8 @@ public interface BindingContext {
WritableSlice<ValueParameterDescriptor, FunctionDescriptor> DATA_CLASS_COMPONENT_FUNCTION =
Slices.<ValueParameterDescriptor, FunctionDescriptor>sliceBuilder().build();
WritableSlice<ClassDescriptor, FunctionDescriptor> DATA_CLASS_COPY_FUNCTION =
Slices.<ClassDescriptor, FunctionDescriptor>sliceBuilder().build();
WritableSlice<FqName, ClassDescriptor> FQNAME_TO_CLASS_DESCRIPTOR = new BasicWritableSlice<FqName, ClassDescriptor>(DO_NOTHING, true);
WritableSlice<FqName, NamespaceDescriptor> FQNAME_TO_NAMESPACE_DESCRIPTOR =
@@ -91,7 +91,7 @@ public class DeclarationResolver {
resolveConstructorHeaders();
resolveAnnotationStubsOnClassesAndConstructors();
resolveFunctionAndPropertyHeaders();
createComponentFunctionsForDataClasses();
createFunctionsForDataClasses();
importsResolver.processMembersImports(rootScope);
checkRedeclarationsInNamespaces();
checkRedeclarationsInInnerClassNames();
@@ -219,24 +219,22 @@ public class DeclarationResolver {
}
}
private void createComponentFunctionsForDataClasses() {
private void createFunctionsForDataClasses() {
for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
JetClass jetClass = entry.getKey();
MutableClassDescriptor classDescriptor = entry.getValue();
if (jetClass.hasPrimaryConstructor() && KotlinBuiltIns.getInstance().isData(classDescriptor)) {
createComponentFunctions(classDescriptor);
ConstructorDescriptor constructor = DescriptorUtils.getConstructorOfDataClass(classDescriptor);
createComponentFunctions(classDescriptor, constructor);
createCopyFunction(classDescriptor, constructor);
}
}
}
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();
private void createComponentFunctions(@NotNull MutableClassDescriptor classDescriptor, @NotNull ConstructorDescriptor constructorDescriptor) {
int parameterIndex = 0;
for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
for (ValueParameterDescriptor parameter : constructorDescriptor.getValueParameters()) {
if (!ErrorUtils.isErrorType(parameter.getType())) {
PropertyDescriptor property = trace.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter);
if (property != null) {
@@ -251,6 +249,13 @@ public class DeclarationResolver {
}
}
private void createCopyFunction(@NotNull MutableClassDescriptor classDescriptor, @NotNull ConstructorDescriptor constructorDescriptor) {
SimpleFunctionDescriptor functionDescriptor = DescriptorResolver.createCopyFunctionDescriptor(
constructorDescriptor.getValueParameters(), classDescriptor, trace);
classDescriptor.getBuilder().addFunctionDescriptor(functionDescriptor);
}
private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) {
if (classDescriptor.getKind() == ClassKind.TRAIT) {
JetParameterList primaryConstructorParameterList = klass.getPrimaryConstructorParameterList();
@@ -356,8 +361,8 @@ public class DeclarationResolver {
descriptorMap.put(desc.getName(), desc);
}
}
reportRedeclarations(descriptorMap);
reportRedeclarations(descriptorMap);
}
}
@@ -392,5 +397,5 @@ public class DeclarationResolver {
}
}
}
@@ -57,6 +57,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 Name COPY_METHOD_NAME = Name.identifier("copy");
public static final String COMPONENT_FUNCTION_NAME_PREFIX = "component";
@NotNull
@@ -349,6 +350,53 @@ public class DescriptorResolver {
return functionDescriptor;
}
@NotNull
public static SimpleFunctionDescriptor createCopyFunctionDescriptor(
@NotNull Collection<ValueParameterDescriptor> constructorParameters,
@NotNull ClassDescriptor classDescriptor,
@NotNull BindingTrace trace
) {
JetType returnType = classDescriptor.getDefaultType();
SimpleFunctionDescriptorImpl functionDescriptor = new SimpleFunctionDescriptorImpl(
classDescriptor,
Collections.<AnnotationDescriptor>emptyList(),
COPY_METHOD_NAME,
CallableMemberDescriptor.Kind.SYNTHESIZED
);
List<ValueParameterDescriptor> parameterDescriptors = Lists.newArrayList();
for (ValueParameterDescriptor parameter : constructorParameters) {
PropertyDescriptor propertyDescriptor = trace.getBindingContext().get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter);
// If parameter hasn't corresponding property, so it mustn't have default value as a parameter in copy function for data class
boolean declaresDefaultValue = propertyDescriptor != null;
ValueParameterDescriptorImpl parameterDescriptor =
new ValueParameterDescriptorImpl(functionDescriptor, parameter.getIndex(), parameter.getAnnotations(),
parameter.getName(), parameter.isVar(), parameter.getType(),
declaresDefaultValue,
parameter.getVarargElementType());
parameterDescriptors.add(parameterDescriptor);
if (declaresDefaultValue) {
trace.record(BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameterDescriptor, propertyDescriptor);
}
}
functionDescriptor.initialize(
null,
classDescriptor.getImplicitReceiver(),
Collections.<TypeParameterDescriptor>emptyList(),
parameterDescriptors,
returnType,
Modality.FINAL,
classDescriptor.getVisibility(),
true
);
trace.record(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor, functionDescriptor);
return functionDescriptor;
}
public static Visibility getDefaultVisibility(JetModifierListOwner modifierListOwner, DeclarationDescriptor containingDescriptor) {
Visibility defaultVisibility;
if (containingDescriptor instanceof ClassDescriptor) {
@@ -365,4 +365,10 @@ public class DescriptorUtils {
+ (classifier == null ? "null" : classifier.getClass());
return (ClassDescriptor) classifier;
}
public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) {
Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
assert constructors.size() == 1 : "Data class must have only one constructor: " + constructors;
return constructors.iterator().next();
}
}
@@ -174,6 +174,12 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
break;
}
}
if (!constructor.getValueParameters().isEmpty() && name.equals(DescriptorResolver.COPY_METHOD_NAME)) {
SimpleFunctionDescriptor copyFunctionDescriptor = DescriptorResolver.createCopyFunctionDescriptor(
constructor.getValueParameters(),
thisDescriptor, resolveSession.getTrace());
result.add(copyFunctionDescriptor);
}
}
private void generateEnumClassObjectMethods(@NotNull Collection<? super FunctionDescriptor> result, @NotNull Name name) {
@@ -307,6 +313,7 @@ public class LazyClassMemberScope extends AbstractLazyMemberScope<LazyClassDescr
if (functions.isEmpty()) break;
n++;
}
getFunctions(Name.identifier("copy"));
}
@Override