Generate copy function for data classes
#KT-2779 Fixed
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user