Skip to content

Commit

Permalink
[lang][ui] Cloning of type references with full type parameter support.
Browse files Browse the repository at this point in the history
see #787
see #799

Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Jan 16, 2018
1 parent 04ab10a commit 084c13f
Show file tree
Hide file tree
Showing 12 changed files with 902 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package io.sarl.lang.ui.quickfix.acceptors;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -176,7 +177,7 @@ public void apply(EObject element, IModificationContext context) throws Exceptio
builder.setBodyGenerator(null);

builder.setVisibility(operation.getVisibility());
builder.setTypeParameters(cloneTypeParameters(operation));
builder.setTypeParameters(cloneTypeParameters(operation, declaringType));

final QualifiedActionName qualifiedActionName = this.actionPrototypeProvider.createQualifiedActionName(
declaringType,
Expand Down Expand Up @@ -311,7 +312,7 @@ private static String typeParameterId(JvmTypeReference type) {
return type.getQualifiedName();
}

/** Clone the given types by applying thee type parameter mapping when necessary.
/** Clone the given types by applying the type parameter mapping when necessary.
*
* @param types the types to clone.
* @param typeParameterMap the type parameter mapping.
Expand All @@ -332,17 +333,21 @@ private LightweightTypeReference cloneTypeReference(JvmTypeReference type,
return Utils.toLightweightTypeReference(mappedReference, this.services);
}

private List<JvmTypeParameter> cloneTypeParameters(JvmOperation fromOperation) {
private List<JvmTypeParameter> cloneTypeParameters(JvmOperation fromOperation, JvmDeclaredType declaringType) {
final SARLQuickfixProvider tools = getTools();
final JvmTypeReferenceBuilder builder1 = tools.getJvmTypeParameterBuilder();
final JvmTypesBuilder builder2 = tools.getJvmTypeBuilder();
final TypeReferences builder3 = tools.getTypeServices().getTypeReferences();
final TypesFactory builder4 = tools.getTypeServices().getTypesFactory();
final List<JvmTypeParameter> outParameters = new ArrayList<>();
// Get the type parameter mapping that is a consequence of the super type extension within the container.
final Map<String, JvmTypeReference> superTypeParameterMapping = new HashMap<>();
Utils.getSuperTypeParameterMap(declaringType, superTypeParameterMapping);
Utils.copyTypeParametersFromJvmOperation(
fromOperation.getTypeParameters(),
outParameters,
builder1, builder2, builder3, builder4, null);
superTypeParameterMapping,
builder1, builder2, builder3, builder4);
return outParameters;
}

Expand Down

Large diffs are not rendered by default.

161 changes: 86 additions & 75 deletions main/coreplugins/io.sarl.lang/src/io/sarl/lang/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import com.google.common.base.Strings;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.core.Flags;
import org.eclipse.xtend.core.jvmmodel.XtendJvmModelInferrer;
Expand All @@ -67,6 +66,7 @@
import org.eclipse.xtext.common.types.JvmType;
import org.eclipse.xtext.common.types.JvmTypeConstraint;
import org.eclipse.xtext.common.types.JvmTypeParameter;
import org.eclipse.xtext.common.types.JvmTypeParameterDeclarator;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.common.types.JvmUpperBound;
import org.eclipse.xtext.common.types.JvmVisibility;
Expand All @@ -83,7 +83,6 @@
import org.eclipse.xtext.xbase.annotations.xAnnotations.XAnnotation;
import org.eclipse.xtext.xbase.annotations.xAnnotations.XAnnotationElementValuePair;
import org.eclipse.xtext.xbase.compiler.ImportManager;
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociator;
import org.eclipse.xtext.xbase.jvmmodel.JvmTypeReferenceBuilder;
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
Expand Down Expand Up @@ -1393,43 +1392,21 @@ public static String dump(Object object, boolean includeStaticField) {
* related to the type parameter of the type container.
*
* @param type the source type.
* @param forOperation the operation that will contain the result type.
* @param executableTypeParameters the type parameters of the executable component that will contain the result type.
* @param superTypeParameterMapping the mapping from the type parameters inherited from the super types.
* @param typeParameterBuilder the builder if type parameter.
* @param typeBuilder the builder of type.
* @param typeReferences the builder of type references.
* @param jvmTypesFactory the factory of Jvm types.
* @param associator the associator to use, or {@code null} if none.
* @return the result type, i.e. a copy of the source type.
* @since 0.6
*/
public static JvmTypeReference cloneWithTypeParametersAndProxies(JvmTypeReference type, JvmOperation forOperation,
public static JvmTypeReference cloneWithTypeParametersAndProxies(
JvmTypeReference type,
Iterable<JvmTypeParameter> executableTypeParameters,
Map<String, JvmTypeReference> superTypeParameterMapping,
JvmTypeReferenceBuilder typeParameterBuilder, JvmTypesBuilder typeBuilder,
TypeReferences typeReferences, TypesFactory jvmTypesFactory,
IJvmModelAssociator associator) {
return cloneWithTypeParametersAndProxies(type, forOperation.getTypeParameters(),
typeParameterBuilder, typeBuilder, typeReferences, jvmTypesFactory, associator);
}

/** Clone the given type reference that for being link to the given operation.
*
* <p>The proxies are not resolved, and the type parameters are clone when they are
* related to the type parameter of the type container.
*
* @param type the source type.
* @param typeParameters the type parameters of the operation that will contain the result type.
* @param typeParameterBuilder the builder if type parameter.
* @param typeBuilder the builder of type.
* @param typeReferences the builder of type references.
* @param jvmTypesFactory the factory of Jvm types.
* @param associator the associator to use, or {@code null} if none.
* @return the result type, i.e. a copy of the source type.
* @since 0.6
*/
public static JvmTypeReference cloneWithTypeParametersAndProxies(JvmTypeReference type,
List<JvmTypeParameter> typeParameters,
JvmTypeReferenceBuilder typeParameterBuilder, JvmTypesBuilder typeBuilder,
TypeReferences typeReferences, TypesFactory jvmTypesFactory,
IJvmModelAssociator associator) {
TypeReferences typeReferences, TypesFactory jvmTypesFactory) {
if (type == null) {
return typeParameterBuilder.typeRef(Object.class);
}
Expand All @@ -1438,23 +1415,30 @@ public static JvmTypeReference cloneWithTypeParametersAndProxies(JvmTypeReferenc
JvmTypeReference typeCandidate = type;

// Use also cloneType as a flag that indicates if the type was already found in type parameters.
if (!typeParameters.isEmpty() && cloneType) {
if ((executableTypeParameters.iterator().hasNext() || !superTypeParameterMapping.isEmpty()) && cloneType) {
final Map<String, JvmTypeParameter> typeParameterIdentifiers = new TreeMap<>();
for (final JvmTypeParameter typeParameter : executableTypeParameters) {
typeParameterIdentifiers.put(typeParameter.getIdentifier(), typeParameter);
}

if (type instanceof JvmParameterizedTypeReference) {
// Try to clone the type parameters.
cloneType = false;
typeCandidate = cloneAndAssociate(type, typeParameters, typeParameterBuilder,
typeReferences, jvmTypesFactory, associator);
typeCandidate = cloneAndAssociate(type, typeParameterIdentifiers, superTypeParameterMapping,
typeParameterBuilder, typeReferences, jvmTypesFactory);
} else if (type instanceof XFunctionTypeRef) {
// Try to clone the function reference.
final XFunctionTypeRef functionRef = (XFunctionTypeRef) type;
cloneType = false;
final XFunctionTypeRef cloneReference = XtypeFactory.eINSTANCE.createXFunctionTypeRef();
for (final JvmTypeReference paramType : functionRef.getParamTypes()) {
cloneReference.getParamTypes().add(cloneAndAssociate(paramType, typeParameters, typeParameterBuilder,
typeReferences, jvmTypesFactory, associator));
cloneReference.getParamTypes().add(cloneAndAssociate(
paramType, typeParameterIdentifiers, superTypeParameterMapping,
typeParameterBuilder, typeReferences, jvmTypesFactory));
}
cloneReference.setReturnType(cloneAndAssociate(functionRef.getReturnType(), typeParameters,
typeParameterBuilder, typeReferences, jvmTypesFactory, associator));
cloneReference.setReturnType(cloneAndAssociate(
functionRef.getReturnType(), typeParameterIdentifiers, superTypeParameterMapping,
typeParameterBuilder, typeReferences, jvmTypesFactory));
cloneReference.setInstanceContext(functionRef.isInstanceContext());
typeCandidate = cloneReference;
}
Expand All @@ -1473,33 +1457,18 @@ public static JvmTypeReference cloneWithTypeParametersAndProxies(JvmTypeReferenc

private static JvmTypeReference cloneAndAssociate(
final JvmTypeReference type,
final List<JvmTypeParameter> typeParameters,
final Map<String, JvmTypeParameter> typeParameterIdentifiers,
Map<String, JvmTypeReference> superTypeParameterMapping,
JvmTypeReferenceBuilder typeParameterBuilder,
TypeReferences typeReferences,
TypesFactory jvmTypesFactory,
IJvmModelAssociator associator) {
final Map<String, JvmTypeParameter> typeParameterIdentifiers = new TreeMap<>();
for (final JvmTypeParameter typeParameter : typeParameters) {
typeParameterIdentifiers.put(typeParameter.getIdentifier(), typeParameter);
}

TypesFactory jvmTypesFactory) {
final EcoreUtil.Copier copier = new EcoreUtil.Copier(false) {
private static final long serialVersionUID = 698510355384773254L;

@Override
protected EObject createCopy(EObject eobject) {
final EObject result = super.createCopy(eobject);
if (result != null && eobject != null && !eobject.eIsProxy()) {
if (associator != null) {
associator.associate(eobject, result);
}
}
return result;
}

@Override
public EObject copy(EObject eobject) {
final String id;
// Try to override the type parameters
if (eobject instanceof JvmTypeReference) {
id = ((JvmTypeReference) eobject).getIdentifier();
} else if (eobject instanceof JvmIdentifiableElement) {
Expand All @@ -1512,6 +1481,10 @@ public EObject copy(EObject eobject) {
if (param != null) {
return typeReferences.createTypeRef(param);
}
final JvmTypeReference superTypeReference = superTypeParameterMapping.get(id);
if (superTypeReference != null) {
return typeReferences.createDelegateTypeReference(superTypeReference);
}
}
final EObject result = super.copy(eobject);
if (result instanceof JvmWildcardTypeReference) {
Expand All @@ -1533,43 +1506,81 @@ public EObject copy(EObject eobject) {
}
return result;
}

@Override
protected void copyReference(EReference ereference, EObject eobject, EObject copyEObject) {
super.copyReference(ereference, eobject, copyEObject);
}
};
final JvmTypeReference copy = (JvmTypeReference) copier.copy(type);
copier.copyReferences();
return copy;
}

/** Extract the mapping between the type parameters declared within the super types and the
* type parameters arguments that are declared within the given type.
*
* <p>For example, consider the following code:
* <pre><code>
* interface X&lt;T&gt; {
* def a(p1 : T, p2 : U) with U
* }
* interface Y&lt;T&gt; {
* }
* class Z&lt;TT&gt; implements X&lt;TT&gt;, Y&lt;TT&gt; {
* def a(p1 : TT, p2 : W) with W { }
* }
* </code></pre>
* The mapping is:
* <pre><code>
* X.T =&gt; TT
* Y.T =&gt; TT
* </code></pre>
*
* @param type the type to analyze.
* @param mapping the map to fill with the mapping.
* @since 0.7
*/
public static void getSuperTypeParameterMap(JvmDeclaredType type, Map<String, JvmTypeReference> mapping) {
for (final JvmTypeReference superTypeReference : type.getSuperTypes()) {
if (superTypeReference instanceof JvmParameterizedTypeReference) {
final JvmParameterizedTypeReference parameterizedTypeReference = (JvmParameterizedTypeReference) superTypeReference;
final JvmType st = superTypeReference.getType();
if (st instanceof JvmTypeParameterDeclarator) {
final JvmTypeParameterDeclarator superType = (JvmTypeParameterDeclarator) st;
int i = 0;
for (final JvmTypeParameter typeParameter : superType.getTypeParameters()) {
mapping.put(typeParameter.getIdentifier(), parameterizedTypeReference.getArguments().get(i));
++i;
}
}
}
}
}

/** Copy the type parameters from a JvmOperation.
*
* <p>This function differs from {@link XtendJvmModelInferrer#copyAndFixTypeParameters(List,
* org.eclipse.xtext.common.types.JvmTypeParameterDeclarator)}
* and {@link XtendJvmModelInferrer#copyTypeParameters(List, org.eclipse.xtext.common.types.JvmTypeParameterDeclarator)}
* in the fact that the type parameters were already generated and fixed. The current function supper generic types by
* clone the types references with {@link #cloneWithTypeParametersAndProxies(JvmTypeReference, JvmOperation,
* JvmTypeReferenceBuilder, JvmTypesBuilder, TypeReferences, TypesFactory, IJvmModelAssociator)}.
* clone the types references with {@link #cloneWithTypeParametersAndProxies(JvmTypeReference, Iterable, Map, JvmTypeReferenceBuilder,
* JvmTypesBuilder, TypeReferences, TypesFactory)}.
*
* @param fromOperation the operation from which the type parameters are copied.
* @param toOperation the operation that will receives the new type parameters.
* @param typeParameterBuilder the builder if type parameter.
* @param typeBuilder the builder of type.
* @param typeReferences the builder of type references.
* @param jvmTypesFactory the factory of Jvm types.
* @param associator the associator to use, or {@code null} if none.
* @since 0.6
*/
public static void copyTypeParametersFromJvmOperation(JvmOperation fromOperation, JvmOperation toOperation,
JvmTypeReferenceBuilder typeParameterBuilder, JvmTypesBuilder typeBuilder,
TypeReferences typeReferences, TypesFactory jvmTypesFactory,
IJvmModelAssociator associator) {
TypeReferences typeReferences, TypesFactory jvmTypesFactory) {
// Get the type parameter mapping that is a consequence of the super type extension within the container.
final Map<String, JvmTypeReference> superTypeParameterMapping = new HashMap<>();
Utils.getSuperTypeParameterMap(toOperation.getDeclaringType(), superTypeParameterMapping);
copyTypeParametersFromJvmOperation(
fromOperation.getTypeParameters(),
toOperation.getTypeParameters(),
typeParameterBuilder, typeBuilder, typeReferences, jvmTypesFactory, associator);
superTypeParameterMapping,
typeParameterBuilder, typeBuilder, typeReferences, jvmTypesFactory);
}

/** Copy the type parameters from a JvmOperation.
Expand All @@ -1578,23 +1589,23 @@ public static void copyTypeParametersFromJvmOperation(JvmOperation fromOperation
* org.eclipse.xtext.common.types.JvmTypeParameterDeclarator)}
* and {@link XtendJvmModelInferrer#copyTypeParameters(List, org.eclipse.xtext.common.types.JvmTypeParameterDeclarator)}
* in the fact that the type parameters were already generated and fixed. The current function supper generic types by
* clone the types references with {@link #cloneWithTypeParametersAndProxies(JvmTypeReference, JvmOperation,
* JvmTypeReferenceBuilder, JvmTypesBuilder, TypeReferences, TypesFactory, IJvmModelAssociator)}.
* clone the types references with {@link #cloneWithTypeParametersAndProxies(JvmTypeReference, Iterable, Map, JvmTypeReferenceBuilder,
* JvmTypesBuilder, TypeReferences, TypesFactory)}.
*
* @param inputParameters the type parameters in the source operation.
* @param outputParameters the list of type parameters to be filled out.
* @param superTypeParameterMapping the mapping from the type parameters inherited from the super types.
* @param typeParameterBuilder the builder if type parameter.
* @param typeBuilder the builder of type.
* @param typeReferences the builder of type references.
* @param jvmTypesFactory the factory of Jvm types.
* @param associator the associator to use, or {@code null} if none.
* @since 0.6
*/
public static void copyTypeParametersFromJvmOperation(List<JvmTypeParameter> inputParameters,
List<JvmTypeParameter> outputParameters,
Map<String, JvmTypeReference> superTypeParameterMapping,
JvmTypeReferenceBuilder typeParameterBuilder, JvmTypesBuilder typeBuilder,
TypeReferences typeReferences, TypesFactory jvmTypesFactory,
IJvmModelAssociator associator) {
TypeReferences typeReferences, TypesFactory jvmTypesFactory) {
// Copy the generic types in two steps: first step is the name's copy.
for (final JvmTypeParameter typeParameter : inputParameters) {
final JvmTypeParameter typeParameterCopy = jvmTypesFactory.createJvmTypeParameter();
Expand All @@ -1617,8 +1628,8 @@ public static void copyTypeParametersFromJvmOperation(List<JvmTypeParameter> inp
cst.setTypeReference(cloneWithTypeParametersAndProxies(
constraint.getTypeReference(),
outputParameters,
typeParameterBuilder, typeBuilder, typeReferences, jvmTypesFactory,
associator));
superTypeParameterMapping,
typeParameterBuilder, typeBuilder, typeReferences, jvmTypesFactory));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public void compiling_02() throws Exception {
" }",
" ",
" @SyntheticMember",
" public Tuple2f(final Collection<? extends ?> arg0) {",
" public Tuple2f(final Collection<? extends T> arg0) {",
" super(arg0);",
" }",
" ",
Expand Down Expand Up @@ -395,7 +395,7 @@ public void compiling_03() throws Exception {
" }",
" ",
" @SyntheticMember",
" public Tuple2f(final Collection<? extends ?> arg0) {",
" public Tuple2f(final Collection<? extends T> arg0) {",
" super(arg0);",
" }",
" ",
Expand Down Expand Up @@ -758,7 +758,7 @@ public void compiling_02() throws Exception {
" }",
" ",
" @SyntheticMember",
" public Tuple2f(final Collection<? extends ?> arg0) {",
" public Tuple2f(final Collection<? extends T> arg0) {",
" super(arg0);",
" }",
" ",
Expand Down Expand Up @@ -835,7 +835,7 @@ public void compiling_03() throws Exception {
" }",
" ",
" @SyntheticMember",
" public Tuple2f(final Collection<? extends ?> arg0) {",
" public Tuple2f(final Collection<? extends T> arg0) {",
" super(arg0);",
" }",
" ",
Expand Down
Loading

0 comments on commit 084c13f

Please sign in to comment.