Create from usage: Refactored invoke().
This commit is contained in:
@@ -193,7 +193,6 @@ public class CreateMethodFromUsageFix extends CreateFromUsageFixBase {
|
|||||||
assert editor != null;
|
assert editor != null;
|
||||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||||
assert file != null && file instanceof JetFile;
|
assert file != null && file instanceof JetFile;
|
||||||
JetFile jetFile = (JetFile) file;
|
|
||||||
PsiElement elementAt = file.findElementAt(offset);
|
PsiElement elementAt = file.findElementAt(offset);
|
||||||
JetFunction func = PsiTreeUtil.getParentOfType(elementAt, JetFunction.class);
|
JetFunction func = PsiTreeUtil.getParentOfType(elementAt, JetFunction.class);
|
||||||
assert func != null;
|
assert func != null;
|
||||||
@@ -426,16 +425,90 @@ public class CreateMethodFromUsageFix extends CreateFromUsageFixBase {
|
|||||||
caretModel.moveToOffset(file.getNode().getStartOffset());
|
caretModel.moveToOffset(file.getNode().getStartOffset());
|
||||||
|
|
||||||
TemplateBuilderImpl builder = new TemplateBuilderImpl(file);
|
TemplateBuilderImpl builder = new TemplateBuilderImpl(file);
|
||||||
|
|
||||||
// add return type to the template (if it's not a unit function)
|
|
||||||
if (!isUnit) {
|
if (!isUnit) {
|
||||||
JetTypeReference returnTypeRef = func.getReturnTypeRef();
|
setupReturnTypeTemplate(builder, func, returnType);
|
||||||
assert returnTypeRef != null;
|
}
|
||||||
Expression returnTypeExpression = new TypeExpression(returnType.getPossibleTypes());
|
TypeExpression[] parameterTypeExpressions = setupParameterTypeTemplates(project, builder, parameters, parameterList);
|
||||||
builder.replaceElement(returnTypeRef, returnTypeExpression);
|
|
||||||
|
// add a segment for the parameter list
|
||||||
|
// Note: because TemplateBuilderImpl does not have a replaceElement overload that takes in both a TextRange and alwaysStopAt, we
|
||||||
|
// need to create the segment first and then hack the Expression into the template later. We use this template to update the type
|
||||||
|
// parameter list as the user makes selections in the parameter types, and we need alwaysStopAt to be false so the user can't tab to
|
||||||
|
// it.
|
||||||
|
JetScope scope = getScope(owner, context);
|
||||||
|
TypeParameterListExpression expression = setupTypeParameterListTemplate(builder, func, ownerType, parameterTypeExpressions, scope);
|
||||||
|
|
||||||
|
// the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it
|
||||||
|
TemplateImpl template = (TemplateImpl) builder.buildInlineTemplate();
|
||||||
|
ArrayList<Variable> variables = template.getVariables();
|
||||||
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
|
Collections.swap(variables, i * 2, i * 2 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add parameters to the template
|
// fix up the template to include the expression for the type parameter list
|
||||||
|
variables.add(new Variable(TYPE_PARAMETER_LIST_VARIABLE_NAME, expression, expression, false, true));
|
||||||
|
|
||||||
|
// run the template
|
||||||
|
TemplateManager.getInstance(project).startTemplate(editor, template, new TemplateEditingAdapter() {
|
||||||
|
@Override
|
||||||
|
public void templateFinished(Template template, boolean brokenOff) {
|
||||||
|
// TODO: file templates
|
||||||
|
|
||||||
|
caretModel.moveToOffset(oldOffset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static TypeExpression setupReturnTypeTemplate(@NotNull TemplateBuilder builder, @NotNull JetNamedFunction func,
|
||||||
|
@NotNull TypeOrExpressionThereof returnType) {
|
||||||
|
JetTypeReference returnTypeRef = func.getReturnTypeRef();
|
||||||
|
assert returnTypeRef != null;
|
||||||
|
TypeExpression returnTypeExpression = new TypeExpression(returnType.getPossibleTypes());
|
||||||
|
builder.replaceElement(returnTypeRef, returnTypeExpression);
|
||||||
|
return returnTypeExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static TypeParameterListExpression setupTypeParameterListTemplate(
|
||||||
|
@NotNull TemplateBuilderImpl builder,
|
||||||
|
@NotNull JetNamedFunction func,
|
||||||
|
@NotNull JetType ownerType,
|
||||||
|
@NotNull TypeExpression[] parameterTypeExpressions,
|
||||||
|
@NotNull JetScope scope
|
||||||
|
) {
|
||||||
|
Map<String, String[]> typeParameterMap = new HashMap<String, String[]>();
|
||||||
|
Set<TypeParameterDescriptor> ownerTypeParameters = getTypeParametersInType(ownerType);
|
||||||
|
String[] ownerTypeParameterNames = getTypeParameterNamesNotInScope(ownerTypeParameters, scope);
|
||||||
|
for (TypeExpression parameterTypeExpression : parameterTypeExpressions) {
|
||||||
|
JetType[] parameterTypeOptions = parameterTypeExpression.getOptions();
|
||||||
|
String[] parameterTypeOptionStrings = parameterTypeExpression.getOptionStrings();
|
||||||
|
assert parameterTypeOptions.length == parameterTypeOptionStrings.length;
|
||||||
|
for (int i = 0; i < parameterTypeOptions.length; i++) {
|
||||||
|
Set<TypeParameterDescriptor> typeParameters = getTypeParametersInType(parameterTypeOptions[i]);
|
||||||
|
typeParameterMap.put(parameterTypeOptionStrings[i], getTypeParameterNamesNotInScope(typeParameters, scope));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.replaceElement(func, TextRange.create(3, 3), TYPE_PARAMETER_LIST_VARIABLE_NAME, null, false); // ((3, 3) is after "fun")
|
||||||
|
return new TypeParameterListExpression(ownerTypeParameterNames, typeParameterMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static JetScope getScope(@NotNull PsiElement owner, @NotNull BindingContext context) {
|
||||||
|
DeclarationDescriptor ownerDescriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, owner);
|
||||||
|
assert ownerDescriptor != null;
|
||||||
|
if (ownerDescriptor instanceof NamespaceDescriptor) {
|
||||||
|
NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) ownerDescriptor;
|
||||||
|
return namespaceDescriptor.getMemberScope();
|
||||||
|
} else {
|
||||||
|
ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
|
||||||
|
return classDescriptor.getMemberScope(classDescriptor.getDefaultType().getArguments());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeExpression[] setupParameterTypeTemplates(@NotNull Project project, @NotNull TemplateBuilder builder,
|
||||||
|
@NotNull List<Parameter> parameters, @NotNull JetParameterList parameterList) {
|
||||||
List<JetParameter> jetParameters = parameterList.getParameters();
|
List<JetParameter> jetParameters = parameterList.getParameters();
|
||||||
assert jetParameters.size() == parameters.size();
|
assert jetParameters.size() == parameters.size();
|
||||||
TypeExpression[] parameterTypeExpressions = new TypeExpression[parameters.size()];
|
TypeExpression[] parameterTypeExpressions = new TypeExpression[parameters.size()];
|
||||||
@@ -477,57 +550,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageFixBase {
|
|||||||
assert parameterNameIdentifier != null;
|
assert parameterNameIdentifier != null;
|
||||||
builder.replaceElement(parameterNameIdentifier, parameterNameExpression);
|
builder.replaceElement(parameterNameIdentifier, parameterNameExpression);
|
||||||
}
|
}
|
||||||
|
return parameterTypeExpressions;
|
||||||
// add a segment for the parameter list
|
|
||||||
// Note: because TemplateBuilderImpl does not have a replaceElement overload that takes in both a TextRange and alwaysStopAt, we
|
|
||||||
// need to create the segment first and then hack the Expression into the template later. We use this template to update the type
|
|
||||||
// parameter list as the user makes selections in the parameter types, and we need alwaysStopAt to be false so the user can't tab to
|
|
||||||
// it.
|
|
||||||
Map<String, String[]> typeParameterMap = new HashMap<String, String[]>();
|
|
||||||
DeclarationDescriptor ownerDescriptor = context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, owner);
|
|
||||||
JetScope scope;
|
|
||||||
if (ownerDescriptor instanceof NamespaceDescriptor) {
|
|
||||||
NamespaceDescriptor namespaceDescriptor = (NamespaceDescriptor) ownerDescriptor;
|
|
||||||
scope = namespaceDescriptor.getMemberScope();
|
|
||||||
} else {
|
|
||||||
ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
|
|
||||||
scope = classDescriptor.getMemberScope(classDescriptor.getDefaultType().getArguments());
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<TypeParameterDescriptor> ownerTypeParameters = getTypeParametersInType(ownerType);
|
|
||||||
String[] ownerTypeParameterNames = getTypeParameterNamesNotInScope(ownerTypeParameters, scope);
|
|
||||||
for (TypeExpression parameterTypeExpression : parameterTypeExpressions) {
|
|
||||||
JetType[] parameterTypeOptions = parameterTypeExpression.getOptions();
|
|
||||||
String[] parameterTypeOptionStrings = parameterTypeExpression.getOptionStrings();
|
|
||||||
assert parameterTypeOptions.length == parameterTypeOptionStrings.length;
|
|
||||||
for (int i = 0; i < parameterTypeOptions.length; i++) {
|
|
||||||
Set<TypeParameterDescriptor> typeParameters = getTypeParametersInType(parameterTypeOptions[i]);
|
|
||||||
typeParameterMap.put(parameterTypeOptionStrings[i], getTypeParameterNamesNotInScope(typeParameters, scope));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression expression = new TypeParameterListExpression(ownerTypeParameterNames, typeParameterMap);
|
|
||||||
builder.replaceElement(func, TextRange.create(3, 3), TYPE_PARAMETER_LIST_VARIABLE_NAME, null, false); // ((3, 3) is after "fun")
|
|
||||||
|
|
||||||
// the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it
|
|
||||||
TemplateImpl template = (TemplateImpl) builder.buildInlineTemplate();
|
|
||||||
ArrayList<Variable> variables = template.getVariables();
|
|
||||||
for (int i = 0; i < parameters.size(); i++) {
|
|
||||||
Collections.swap(variables, i * 2, i * 2 + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix up the template to include the expression for the type parameter list
|
|
||||||
variables.add(new Variable(TYPE_PARAMETER_LIST_VARIABLE_NAME, expression, expression, false, true));
|
|
||||||
|
|
||||||
// run the template
|
|
||||||
TemplateManager.getInstance(project).startTemplate(editor, template, new TemplateEditingAdapter() {
|
|
||||||
@Override
|
|
||||||
public void templateFinished(Template template, boolean brokenOff) {
|
|
||||||
// TODO: file templates
|
|
||||||
|
|
||||||
caretModel.moveToOffset(oldOffset);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user