diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java deleted file mode 100644 index ded5099ff17..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.java +++ /dev/null @@ -1,1437 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.quickfix; - -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.lookup.LookupElement; -import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.codeInsight.navigation.NavigationUtil; -import com.intellij.codeInsight.template.*; -import com.intellij.codeInsight.template.impl.TemplateImpl; -import com.intellij.codeInsight.template.impl.Variable; -import com.intellij.ide.fileTemplates.FileTemplate; -import com.intellij.ide.fileTemplates.FileTemplateManager; -import com.intellij.ide.util.PsiElementListCellRenderer; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.editor.CaretModel; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.popup.PopupChooserBuilder; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiReference; -import com.intellij.psi.search.SearchScope; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.psi.SearchUtils; -import com.intellij.ui.components.JBList; -import com.intellij.util.ArrayUtil; -import com.intellij.util.IncorrectOperationException; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.analyzer.AnalyzeExhaust; -import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.diagnostics.Diagnostic; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1; -import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2; -import org.jetbrains.jet.lang.diagnostics.Errors; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; -import org.jetbrains.jet.lang.resolve.DescriptorUtils; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.types.*; -import org.jetbrains.jet.lang.types.checker.JetTypeChecker; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import org.jetbrains.jet.plugin.JetBundle; -import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage; -import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil; -import org.jetbrains.jet.plugin.codeInsight.ShortenReferences; -import org.jetbrains.jet.plugin.presentation.JetClassPresenter; -import org.jetbrains.jet.plugin.refactoring.JetNameSuggester; -import org.jetbrains.jet.plugin.refactoring.JetNameValidator; -import org.jetbrains.jet.plugin.references.JetSimpleNameReference; - -import javax.swing.*; -import java.awt.*; -import java.util.*; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class CreateFunctionFromUsageFix extends CreateFromUsageFixBase { - private static final String TYPE_PARAMETER_LIST_VARIABLE_NAME = "typeParameterList"; - private static final String TEMPLATE_FROM_USAGE_FUNCTION_BODY = "New Kotlin Function Body.kt"; - private static final String ATTRIBUTE_FUNCTION_NAME = "FUNCTION_NAME"; - private static final Pattern COMPONENT_FUNCTION_PATTERN = Pattern.compile("^component(\\d+)$"); - - /** - * Represents a single choice for a type (e.g. parameter type or return type). - */ - private static class TypeCandidate { - private final JetType type; - private final TypeParameterDescriptor[] typeParameters; - private String renderedType; - private String[] typeParameterNames; - - public TypeCandidate(@NotNull JetType type) { - this.type = type; - Set typeParametersInType = getTypeParametersInType(type); - typeParameters = typeParametersInType.toArray(new TypeParameterDescriptor[typeParametersInType.size()]); - renderedType = renderTypeShort(type, Collections.emptyMap()); - } - - public TypeCandidate(@NotNull JetType type, @NotNull JetScope scope) { - this.type = type; - typeParameters = getTypeParameterNamesNotInScope(getTypeParametersInType(type), scope); - } - - public void render(@NotNull Map typeParameterNameMap) { - renderedType = renderTypeShort(type, typeParameterNameMap); - typeParameterNames = new String[typeParameters.length]; - int i = 0; - for (TypeParameterDescriptor typeParameter : typeParameters) { - typeParameterNames[i] = typeParameterNameMap.get(typeParameter); - i++; - } - } - - @NotNull - JetType getType() { - return type; - } - - @NotNull - public String getRenderedType() { - assert renderedType != null : "call render() first"; - return renderedType; - } - - @NotNull - public String[] getTypeParameterNames() { - assert typeParameterNames != null : "call render() first"; - return typeParameterNames; - } - - @NotNull - public TypeParameterDescriptor[] getTypeParameters() { - return typeParameters; - } - } - - /** - * Represents an element in the class selection list. - */ - private static class ClassCandidate { - private final TypeCandidate typeCandidate; - private final JetClass klass; - - public ClassCandidate(TypeCandidate typeCandidate, JetFile file, BindingContext context) { - this.typeCandidate = typeCandidate; - ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(typeCandidate.getType()); - PsiElement element = DescriptorToDeclarationUtil.getDeclaration(file, classDescriptor, context); - assert element instanceof JetClass; - klass = (JetClass) element; - } - - public TypeCandidate getTypeCandidate() { - return typeCandidate; - } - - public JetClass getJetClass() { - return klass; - } - } - - /** - * Renders a ClassCandidate. - */ - private static class ClassCandidateListCellRenderer extends PsiElementListCellRenderer { - private final JetClassPresenter presenter; - - public ClassCandidateListCellRenderer() { - presenter = new JetClassPresenter(); - } - - @Override - public String getElementText(JetClass element) { - return presenter.getPresentation(element).getPresentableText(); - } - - @Nullable - @Override - protected String getContainerText(JetClass element, String name) { - return presenter.getPresentation(element).getLocationString(); - } - - @Override - protected int getIconFlags() { - return 0; - } - - @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - return super.getListCellRendererComponent(list, ((ClassCandidate) value).getJetClass(), index, isSelected, cellHasFocus); - } - } - - /** - * Represents a concrete type or a set of types yet to be inferred from an expression. - */ - private static class TypeOrExpressionThereof { - private final JetExpression expressionOfType; - private final JetType type; - private final Variance variance; - private List typeCandidates; - private String[] cachedNameCandidatesFromExpression; - - public TypeOrExpressionThereof(@NotNull JetExpression expressionOfType, Variance variance) { - this(expressionOfType, null, variance); - } - - public TypeOrExpressionThereof(@NotNull JetType type, Variance variance) { - this(null, type, variance); - } - - private TypeOrExpressionThereof(@Nullable JetExpression expressionOfType, @Nullable JetType type, Variance variance) { - this.expressionOfType = expressionOfType; - this.type = type; - this.variance = variance; - } - - public boolean isType() { - return this.type != null; - } - - @NotNull - public JetType getType() { - assert this.type != null; - return this.type; - } - - @NotNull - private List getPossibleTypes(BindingContext context) { - List types = new ArrayList(); - if (isType()) { - assert type != null : "!isType() means type == null && expressionOfType != null"; - types.add(type); - if (variance == Variance.IN_VARIANCE) { - types.addAll(TypeUtils.getAllSupertypes(type)); - } - } - else { - assert expressionOfType != null : "!isType() means type == null && expressionOfType != null"; - for (JetType type : guessTypesForExpression(expressionOfType, context)) { - types.add(type); - if (variance == Variance.IN_VARIANCE) { - types.addAll(TypeUtils.getAllSupertypes(type)); - } - } - } - return types; - } - - public void computeTypeCandidates(@NotNull BindingContext context) { - Collection types = getPossibleTypes(context); - - typeCandidates = new ArrayList(); - for (JetType type : types) { - typeCandidates.add(new TypeCandidate(type)); - } - } - - public void computeTypeCandidates( - @NotNull BindingContext context, - @NotNull JetTypeSubstitution[] substitutions, - @NotNull JetScope scope - ) { - List types = getPossibleTypes(context); - Collections.reverse(types); // reverse and reverse back later, so that things added below are added at the front - - Set newTypes = new LinkedHashSet(types); - for (JetTypeSubstitution substitution : substitutions) { // each substitution can be applied or not, so we offer all options - List toAdd = new ArrayList(); - List toRemove = new ArrayList(); - for (JetType type : newTypes) { - toAdd.add(substituteType(type, substitution, variance)); - // substitution.byType are type arguments, but they cannot already occur in the type before substitution - if (containsType(type, substitution.getByType())) { - toRemove.add(type); - } - } - newTypes.addAll(toAdd); - newTypes.removeAll(toRemove); - } - - if (newTypes.isEmpty()) { - newTypes.add(KotlinBuiltIns.getInstance().getAnyType()); - } - - typeCandidates = new ArrayList(); - for (JetType type : newTypes) { - typeCandidates.add(new TypeCandidate(type, scope)); - } - Collections.reverse(typeCandidates); // reverse order (see explanation above) - } - - @NotNull - public List getTypeCandidates() { - assert typeCandidates != null : "call computeTypeCandidates() first"; - return typeCandidates; - } - - public void renderTypeCandidates(@NotNull Map typeParameterNameMap) { - for (TypeCandidate candidate : typeCandidates) { - candidate.render(typeParameterNameMap); - } - } - - @NotNull - public String[] getPossibleNamesFromExpression() { - if (cachedNameCandidatesFromExpression != null) return cachedNameCandidatesFromExpression; - if (isType()) { - cachedNameCandidatesFromExpression = ArrayUtil.EMPTY_STRING_ARRAY; - } - else { - assert expressionOfType != null : "!isType() means type == null && expressionOfType != null"; - JetNameValidator dummyValidator = JetNameValidator.getEmptyValidator(expressionOfType.getProject()); - cachedNameCandidatesFromExpression = JetNameSuggester.suggestNamesForExpression(expressionOfType, dummyValidator); - } - return cachedNameCandidatesFromExpression; - } - } - - /** - * Encapsulates information about a function parameter that is going to be created. - */ - private static class Parameter { - private final String preferredName; - private final TypeOrExpressionThereof type; - - public Parameter(@Nullable("no preferred name") String preferredName, TypeOrExpressionThereof type) { - this.preferredName = preferredName; - this.type = type; - } - - public String getPreferredName() { - return preferredName; - } - - public TypeOrExpressionThereof getType() { - return type; - } - } - - /** - * Special Expression for parameter names based on its type. - */ - private static class ParameterNameExpression extends Expression { - private final String[] names; - private final Map parameterTypeToNamesMap; - - public ParameterNameExpression(@NotNull String[] names, @NotNull Map parameterTypeToNamesMap) { - for (String name : names) { - assert name != null && !name.isEmpty(); - } - this.names = names; - this.parameterTypeToNamesMap = parameterTypeToNamesMap; - } - - @Nullable - @Override - public Result calculateResult(ExpressionContext context) { - LookupElement[] lookupItems = calculateLookupItems(context); - if (lookupItems.length == 0) return new TextResult(""); - - return new TextResult(lookupItems[0].getLookupString()); - } - - @Nullable - @Override - public Result calculateQuickResult(ExpressionContext context) { - return calculateResult(context); - } - - @NotNull - @Override - public LookupElement[] calculateLookupItems(ExpressionContext context) { - Set names = new LinkedHashSet(); - Collections.addAll(names, this.names); - - // find the parameter list - Project project = context.getProject(); - int offset = context.getStartOffset(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - Editor editor = context.getEditor(); - assert editor != null; - PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - assert file instanceof JetFile; - PsiElement elementAt = file.findElementAt(offset); - JetFunction func = PsiTreeUtil.getParentOfType(elementAt, JetFunction.class); - if (func == null) return new LookupElement[0]; - JetParameterList parameterList = func.getValueParameterList(); - assert parameterList != null; - - // add names based on selected type - JetParameter parameter = PsiTreeUtil.getParentOfType(elementAt, JetParameter.class); - if (parameter != null) { - JetTypeReference parameterTypeRef = parameter.getTypeReference(); - if (parameterTypeRef != null) { - String[] suggestedNamesBasedOnType = parameterTypeToNamesMap.get(parameterTypeRef.getText()); - if (suggestedNamesBasedOnType != null) { - Collections.addAll(names, suggestedNamesBasedOnType); - } - } - } - - // remember other parameter names for later use - Set parameterNames = new HashSet(); - for (JetParameter jetParameter : parameterList.getParameters()) { - if (jetParameter == parameter || jetParameter.getName() == null) continue; - parameterNames.add(jetParameter.getName()); - } - - // add fallback parameter name - if (names.isEmpty()) { - names.add("arg"); - } - - // ensure there are no conflicts - List lookupElements = new ArrayList(); - for (String name : names) { - name = getNextAvailableName(name, parameterNames, null); - lookupElements.add(LookupElementBuilder.create(name)); - } - - // create and return - return lookupElements.toArray(new LookupElement[lookupElements.size()]); - } - } - - /** - * An Expression for type references. - */ - private static class TypeExpression extends Expression { - private final TypeOrExpressionThereof type; - private @NotNull LookupElement[] cachedLookupElements; - - public TypeExpression(@NotNull TypeOrExpressionThereof type) { - this.type = type; - List candidates = type.getTypeCandidates(); - cachedLookupElements = new LookupElement[candidates.size()]; - for (int i = 0; i < candidates.size(); i++) { - cachedLookupElements[i] = LookupElementBuilder.create(candidates.get(i), candidates.get(i).getRenderedType()); - } - } - - @Nullable - @Override - public Result calculateResult(ExpressionContext context) { - LookupElement[] lookupItems = calculateLookupItems(context); - if (lookupItems.length == 0) return new TextResult(""); - - return new TextResult(lookupItems[0].getLookupString()); - } - - @Nullable - @Override - public Result calculateQuickResult(ExpressionContext context) { - return calculateResult(context); - } - - @NotNull - @Override - public LookupElement[] calculateLookupItems(ExpressionContext context) { - return cachedLookupElements; - } - - @NotNull - public TypeOrExpressionThereof getType() { - return type; - } - - @Nullable("can't be found") - public JetType getTypeFromSelection(@NotNull String selection) { - for (TypeCandidate option : type.getTypeCandidates()) { - if (option.getRenderedType().equals(selection)) { - return option.getType(); - } - } - return null; - } - } - - /** - * A sort-of dummy Expression for parameter lists, to allow us to update the parameter list as the user makes selections. - */ - private static class TypeParameterListExpression extends Expression { - private final String[] typeParameterNamesFromReceiverType; - private final Map parameterTypeToTypeParameterNamesMap; - - public TypeParameterListExpression( - @NotNull String[] typeParameterNamesFromReceiverType, - @NotNull Map typeParametersMap - ) { - this.typeParameterNamesFromReceiverType = typeParameterNamesFromReceiverType; - this.parameterTypeToTypeParameterNamesMap = typeParametersMap; - } - - @NotNull - @Override - public Result calculateResult(ExpressionContext context) { - Project project = context.getProject(); - int offset = context.getStartOffset(); - PsiDocumentManager.getInstance(project).commitAllDocuments(); - Editor editor = context.getEditor(); - assert editor != null; - PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()); - assert file instanceof JetFile; - PsiElement elementAt = file.findElementAt(offset); - JetFunction func = PsiTreeUtil.getParentOfType(elementAt, JetFunction.class); - if (func == null) { - return new TextResult(""); - } - List parameters = func.getValueParameters(); - - Set typeParameterNames = new LinkedHashSet(); - Collections.addAll(typeParameterNames, typeParameterNamesFromReceiverType); - for (JetParameter parameter : parameters) { - JetTypeReference parameterTypeRef = parameter.getTypeReference(); - if (parameterTypeRef != null) { - String[] typeParameterNamesFromParameter = parameterTypeToTypeParameterNamesMap.get(parameterTypeRef.getText()); - if (typeParameterNamesFromParameter != null) { - Collections.addAll(typeParameterNames, typeParameterNamesFromParameter); - } - } - } - JetTypeReference returnTypeRef = func.getReturnTypeRef(); - if (returnTypeRef != null) { - String[] typeParameterNamesFromReturnType = parameterTypeToTypeParameterNamesMap.get(returnTypeRef.getText()); - if (typeParameterNamesFromReturnType != null) { - Collections.addAll(typeParameterNames, typeParameterNamesFromReturnType); - } - } - - return typeParameterNames.isEmpty() - ? new TextResult("") - : new TextResult(" <" + StringUtil.join(typeParameterNames, ", ") + ">"); - } - - @Nullable - @Override - public Result calculateQuickResult(ExpressionContext context) { - return calculateResult(context); - } - - @NotNull - @Override - public LookupElement[] calculateLookupItems(ExpressionContext context) { - return new LookupElement[0]; // do not offer the user any choices - } - } - - /** - * Encapsulates a single type substitution of a JetType by another JetType. - */ - private static class JetTypeSubstitution { - private final JetType forType; - private final JetType byType; - - private JetTypeSubstitution(JetType forType, JetType byType) { - this.forType = forType; - this.byType = byType; - } - - private JetType getForType() { - return forType; - } - - private JetType getByType() { - return byType; - } - } - - private final String functionName; - private final TypeOrExpressionThereof ownerType; - private final TypeOrExpressionThereof returnType; - private final List parameters; - - private boolean isUnit; - private boolean isExtension; - private JetFile currentFile; - private JetFile containingFile; - private Editor currentFileEditor; - private Editor containingFileEditor; - private BindingContext currentFileContext; - private ModuleDescriptor currentFileModule; - private JetClass ownerClass; - private ClassDescriptor ownerClassDescriptor; - private TypeCandidate selectedReceiverType; - private Map typeParameterNameMap; - - public CreateFunctionFromUsageFix( - @NotNull PsiElement element, @NotNull TypeOrExpressionThereof ownerType, @NotNull String functionName, - @NotNull TypeOrExpressionThereof returnType, @NotNull List parameters - ) { - super(element); - this.functionName = functionName; - this.ownerType = ownerType; - this.returnType = returnType; - this.parameters = parameters; - } - - @NotNull - @Override - public String getText() { - return JetBundle.message("create.function.from.usage", functionName); - } - - @Override - public void invoke(@NotNull final Project project, Editor editor, JetFile file) throws IncorrectOperationException { - currentFile = file; - currentFileEditor = editor; - AnalyzeExhaust exhaust = ResolvePackage.getAnalysisResults(currentFile); - currentFileContext = exhaust.getBindingContext(); - currentFileModule = exhaust.getModuleDescriptor(); - - ownerType.computeTypeCandidates(currentFileContext); - List ownerTypeCandidates = ownerType.getTypeCandidates(); - assert !ownerTypeCandidates.isEmpty(); - if (ownerTypeCandidates.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { - selectedReceiverType = ownerTypeCandidates.get(0); - addFunctionToSelectedOwner(); - } - else { - // class selection - List options = new ArrayList(); - for (TypeCandidate ownerTypeCandidate : ownerTypeCandidates) { - options.add(new ClassCandidate(ownerTypeCandidate, currentFile, currentFileContext)); - } - - final JList list = new JBList(options); - PsiElementListCellRenderer renderer = new ClassCandidateListCellRenderer(); - list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.setCellRenderer(renderer); - PopupChooserBuilder builder = new PopupChooserBuilder(list); - renderer.installSpeedSearch(builder); - - Runnable runnable = new Runnable() { - @Override - public void run() { - ClassCandidate selectedCandidate = (ClassCandidate) list.getSelectedValue(); - if (selectedCandidate == null) return; - selectedReceiverType = selectedCandidate.getTypeCandidate(); - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - @Override - public void run() { - addFunctionToSelectedOwner(); - } - }, getText(), null); - } - }; - - builder.setTitle(JetBundle.message("choose.target.class.or.trait.title")) - .setItemChoosenCallback(runnable) - .createPopup() - .showInBestPositionFor(currentFileEditor); - } - } - - private void addFunctionToSelectedOwner() { - // gather relevant information - ownerClassDescriptor = DescriptorUtils.getClassDescriptorForType(selectedReceiverType.getType()); - JetType receiverType = ownerClassDescriptor.getDefaultType(); - PsiElement classDeclaration = BindingContextUtils.classDescriptorToDeclaration(currentFileContext, ownerClassDescriptor); - if (classDeclaration instanceof JetClass) { - ownerClass = (JetClass) classDeclaration; - isExtension = !ownerClass.isWritable(); - } - else { - isExtension = true; - } - isUnit = returnType.isType() && KotlinBuiltIns.getInstance().isUnit(returnType.getType()); - - JetScope scope; - if (isExtension) { - scope = currentFileModule.getPackage(currentFile.getPackageFqName()).getMemberScope(); - } - else { - scope = ((ClassDescriptorWithResolutionScopes) ownerClassDescriptor).getScopeForMemberDeclarationResolution(); - } - - // figure out type substitutions for type parameters - List classTypeParameters = receiverType.getArguments(); - List ownerTypeArguments = selectedReceiverType.getType().getArguments(); - assert ownerTypeArguments.size() == classTypeParameters.size(); - JetTypeSubstitution[] substitutions = new JetTypeSubstitution[classTypeParameters.size()]; - for (int i = 0; i < substitutions.length; i++) { - substitutions[i] = new JetTypeSubstitution(ownerTypeArguments.get(i).getType(), classTypeParameters.get(i).getType()); - } - for (Parameter parameter : parameters) { - parameter.getType().computeTypeCandidates(currentFileContext, substitutions, scope); - } - if (!isUnit) { - returnType.computeTypeCandidates(currentFileContext, substitutions, scope); - } - - // now that we have done substitutions, we can throw it away - selectedReceiverType = new TypeCandidate(receiverType, scope); - - // figure out type parameter renames to avoid conflicts - typeParameterNameMap = getTypeParameterRenames(scope); - for (Parameter parameter : parameters) { - parameter.getType().renderTypeCandidates(typeParameterNameMap); - } - if (!isUnit) { - returnType.renderTypeCandidates(typeParameterNameMap); - } - selectedReceiverType.render(typeParameterNameMap); - - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - JetNamedFunction func = createFunctionSkeleton(); - buildAndRunTemplate(func); - } - }); - } - - private JetNamedFunction createFunctionSkeleton() { - Project project = currentFile.getProject(); - JetNamedFunction func; - String[] parameterStrings = new String[parameters.size()]; - for (int i = 0; i < parameterStrings.length; i++) { - parameterStrings[i] = "p" + i + ": Any"; - } - String parametersString = StringUtil.join(parameterStrings, ", "); - String returnTypeString = isUnit ? "" : ": Any"; - if (isExtension) { // create as extension function - String ownerTypeString = selectedReceiverType.getRenderedType(); - String functionText = String.format("fun %s.%s(%s)%s { }", ownerTypeString, functionName, parametersString, returnTypeString); - func = JetPsiFactory.createFunction(project, functionText); - containingFile = currentFile; - containingFileEditor = currentFileEditor; - return (JetNamedFunction) currentFile.add(func); - } - else { // create as regular function - String functionText = String.format("fun %s(%s)%s { }", functionName, parametersString, returnTypeString); - func = JetPsiFactory.createFunction(project, functionText); - PsiFile classContainingFile = ownerClass.getContainingFile(); - assert classContainingFile instanceof JetFile; - containingFile = (JetFile) classContainingFile; - - NavigationUtil.activateFileWithPsiElement(containingFile); - containingFileEditor = FileEditorManager.getInstance(project).getSelectedTextEditor(); - - JetClassBody classBody = ownerClass.getBody(); - if (classBody == null) { - classBody = (JetClassBody) ownerClass.add(JetPsiFactory.createEmptyClassBody(project)); - ownerClass.addBefore(JetPsiFactory.createWhiteSpace(project), classBody); - } - PsiElement rBrace = classBody.getRBrace(); - assert rBrace != null; - return (JetNamedFunction) classBody.addBefore(func, rBrace); - } - } - - private void buildAndRunTemplate(@NotNull JetNamedFunction func) { - Project project = func.getProject(); - JetParameterList parameterList = func.getValueParameterList(); - assert parameterList != null; - - // build templates - PsiDocumentManager.getInstance(project).commitAllDocuments(); - PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(containingFileEditor.getDocument()); - - CaretModel caretModel = containingFileEditor.getCaretModel(); - caretModel.moveToOffset(containingFile.getNode().getStartOffset()); - - TemplateBuilderImpl builder = new TemplateBuilderImpl(containingFile); - final TypeExpression returnTypeExpression = isUnit ? null : setupReturnTypeTemplate(builder, func); - final TypeExpression[] parameterTypeExpressions = setupParameterTypeTemplates(builder, parameterList); - - // 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. - TypeParameterListExpression expression = setupTypeParameterListTemplate(builder, func); - - // the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it - final TemplateImpl templateImpl = (TemplateImpl) builder.buildInlineTemplate(); - ArrayList variables = templateImpl.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)); - - // TODO: Disabled shortening names because it causes some tests fail. Refactor code to use automatic reference shortening - templateImpl.setToShortenLongNames(false); - - // run the template - TemplateManager.getInstance(project).startTemplate(containingFileEditor, templateImpl, new TemplateEditingAdapter() { - @Override - public void templateFinished(Template template, boolean brokenOff) { - // file templates - int offset = templateImpl.getSegmentOffset(0); - final JetNamedFunction func = PsiTreeUtil.findElementOfClassAtOffset(containingFile, offset, JetNamedFunction.class, false); - assert func != null; - final List typeRefsToShorten = new ArrayList(); - - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - // file templates - setupFunctionBody(func); - - // change short type names to fully qualified ones (to be shortened below) - setupTypeReferencesForShortening(func, typeRefsToShorten, parameterTypeExpressions, returnTypeExpression); - } - }); - - ShortenReferences.instance$.process(typeRefsToShorten); - } - }); - } - - private Map getTypeParameterRenames(JetScope scope) { - TypeParameterDescriptor[] receiverTypeParametersNotInScope = selectedReceiverType.getTypeParameters(); - Set allTypeParametersNotInScope = new LinkedHashSet(); - allTypeParametersNotInScope.addAll(Arrays.asList(receiverTypeParametersNotInScope)); - - for (Parameter parameter : parameters) { - for (TypeCandidate parameterTypeCandidate : parameter.getType().getTypeCandidates()) { - allTypeParametersNotInScope.addAll(Arrays.asList(parameterTypeCandidate.getTypeParameters())); - } - } - - if (!isUnit) { - for (TypeCandidate returnTypeCandidate : returnType.getTypeCandidates()) { - allTypeParametersNotInScope.addAll(Arrays.asList(returnTypeCandidate.getTypeParameters())); - } - } - - List typeParameters = new ArrayList(allTypeParametersNotInScope); - List typeParameterNames = new ArrayList(); - for (TypeParameterDescriptor typeParameter : typeParameters) { - typeParameterNames.add(getNextAvailableName(typeParameter.getName().asString(), typeParameterNames, scope)); - } - assert typeParameters.size() == typeParameterNames.size(); - Map typeParameterNameMap = new HashMap(); - for (int i = 0; i < typeParameters.size(); i++) { - typeParameterNameMap.put(typeParameters.get(i), typeParameterNames.get(i)); - } - - return typeParameterNameMap; - } - - private void setupTypeReferencesForShortening( - @NotNull JetNamedFunction func, - @NotNull List typeRefsToShorten, - @NotNull TypeExpression[] parameterTypeExpressions, - @Nullable TypeExpression returnTypeExpression - ) { - if (isExtension) { - JetTypeReference receiverTypeRef = - JetPsiFactory.createType(func.getProject(), renderTypeLong(selectedReceiverType.getType(), typeParameterNameMap)); - replaceWithLongerName(receiverTypeRef, selectedReceiverType.getType()); - - receiverTypeRef = func.getReceiverTypeRef(); - if (receiverTypeRef != null) { - typeRefsToShorten.add(receiverTypeRef); - } - } - - if (!isUnit) { - assert returnTypeExpression != null; - JetTypeReference returnTypeRef = func.getReturnTypeRef(); - if (returnTypeRef != null) { - JetType returnType = returnTypeExpression.getTypeFromSelection(returnTypeRef.getText()); - if (returnType != null) { // user selected a given type - replaceWithLongerName(returnTypeRef, returnType); - returnTypeRef = func.getReturnTypeRef(); - assert returnTypeRef != null; - typeRefsToShorten.add(returnTypeRef); - } - } - } - - List valueParameters = func.getValueParameters(); - List parameterIndicesToShorten = new ArrayList(); - assert valueParameters.size() == parameterTypeExpressions.length; - for (int i = 0; i < valueParameters.size(); i++) { - JetParameter parameter = valueParameters.get(i); - JetTypeReference parameterTypeRef = parameter.getTypeReference(); - if (parameterTypeRef != null) { - JetType parameterType = parameterTypeExpressions[i].getTypeFromSelection(parameterTypeRef.getText()); - if (parameterType != null) { - replaceWithLongerName(parameterTypeRef, parameterType); - parameterIndicesToShorten.add(i); - } - } - } - valueParameters = func.getValueParameters(); - for (int i : parameterIndicesToShorten) { - JetTypeReference parameterTypeRef = valueParameters.get(i).getTypeReference(); - if (parameterTypeRef != null) { - typeRefsToShorten.add(parameterTypeRef); - } - } - } - - private void setupFunctionBody(@NotNull JetNamedFunction func) { - FileTemplate fileTemplate = FileTemplateManager.getInstance().getCodeTemplate(TEMPLATE_FROM_USAGE_FUNCTION_BODY); - Properties properties = new Properties(); - if (isUnit) { - properties.setProperty(FileTemplate.ATTRIBUTE_RETURN_TYPE, "Unit"); - } - else { - JetTypeReference returnTypeRef = func.getReturnTypeRef(); - assert returnTypeRef != null; - properties.setProperty(FileTemplate.ATTRIBUTE_RETURN_TYPE, returnTypeRef.getText()); - } - properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(ownerClassDescriptor).asString()); - properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, ownerClassDescriptor.getName().asString()); - properties.setProperty(ATTRIBUTE_FUNCTION_NAME, functionName); - - @NonNls String bodyText; - try { - bodyText = fileTemplate.getText(properties); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Exception e) { - throw new IncorrectOperationException("Failed to parse file template", e); - } - JetExpression newBodyExpression = JetPsiFactory.createFunctionBody(func.getProject(), bodyText); - JetExpression oldBodyExpression = func.getBodyExpression(); - assert oldBodyExpression != null; - oldBodyExpression.replace(newBodyExpression); - } - - @NotNull - private TypeExpression setupReturnTypeTemplate(@NotNull TemplateBuilder builder, @NotNull JetNamedFunction func) { - JetTypeReference returnTypeRef = func.getReturnTypeRef(); - assert returnTypeRef != null; - TypeExpression returnTypeExpression = new TypeExpression(returnType); - builder.replaceElement(returnTypeRef, returnTypeExpression); - return returnTypeExpression; - } - - @NotNull - private TypeParameterListExpression setupTypeParameterListTemplate( - @NotNull TemplateBuilderImpl builder, - @NotNull JetNamedFunction func - ) { - Map typeParameterMap = new HashMap(); - String[] receiverTypeParameterNames = selectedReceiverType.getTypeParameterNames(); - - for (Parameter parameter : parameters) { - for (TypeCandidate parameterTypeCandidate : parameter.getType().getTypeCandidates()) { - typeParameterMap.put(parameterTypeCandidate.getRenderedType(), parameterTypeCandidate.getTypeParameterNames()); - } - } - - JetTypeReference returnTypeRef = func.getReturnTypeRef(); - if (returnTypeRef != null) { - for (TypeCandidate returnTypeCandidate : returnType.getTypeCandidates()) { - typeParameterMap.put(returnTypeCandidate.getRenderedType(), returnTypeCandidate.getTypeParameterNames()); - } - } - - builder.replaceElement(func, TextRange.create(3, 3), TYPE_PARAMETER_LIST_VARIABLE_NAME, null, false); // ((3, 3) is after "fun") - return new TypeParameterListExpression(receiverTypeParameterNames, typeParameterMap); - } - - private TypeExpression[] setupParameterTypeTemplates(@NotNull TemplateBuilder builder, @NotNull JetParameterList parameterList) { - List jetParameters = parameterList.getParameters(); - assert jetParameters.size() == parameters.size(); - TypeExpression[] parameterTypeExpressions = new TypeExpression[parameters.size()]; - JetNameValidator dummyValidator = JetNameValidator.getEmptyValidator(parameterList.getProject()); - for (int i = 0; i < parameters.size(); i++) { - Parameter parameter = parameters.get(i); - JetParameter jetParameter = jetParameters.get(i); - - // add parameter type to the template - parameterTypeExpressions[i] = new TypeExpression(parameter.getType()); - JetTypeReference parameterTypeRef = jetParameter.getTypeReference(); - assert parameterTypeRef != null; - builder.replaceElement(parameterTypeRef, parameterTypeExpressions[i]); - - // add parameter name to the template - String[] possibleNamesFromExpression = parameter.getType().getPossibleNamesFromExpression(); - String preferredName = parameter.getPreferredName(); - String[] possibleNames; - if (preferredName != null) { - possibleNames = new String[possibleNamesFromExpression.length + 1]; - possibleNames[0] = preferredName; - System.arraycopy(possibleNamesFromExpression, 0, possibleNames, 1, possibleNamesFromExpression.length); - } - else { - possibleNames = possibleNamesFromExpression; - } - - // figure out suggested names for each type option - Map parameterTypeToNamesMap = new HashMap(); - for (TypeCandidate typeCandidate : parameter.getType().getTypeCandidates()) { - String[] suggestedNames = JetNameSuggester.suggestNamesForType(typeCandidate.getType(), dummyValidator); - parameterTypeToNamesMap.put(typeCandidate.getRenderedType(), suggestedNames); - } - - // add expression to builder - Expression parameterNameExpression = new ParameterNameExpression(possibleNames, parameterTypeToNamesMap); - PsiElement parameterNameIdentifier = jetParameter.getNameIdentifier(); - assert parameterNameIdentifier != null; - builder.replaceElement(parameterNameIdentifier, parameterNameExpression); - } - return parameterTypeExpressions; - } - - private void replaceWithLongerName(@NotNull JetTypeReference typeRef, @NotNull JetType type) { - Project project = typeRef.getProject(); - JetTypeReference fullyQualifiedReceiverTypeRef = JetPsiFactory.createType(project, renderTypeLong(type, typeParameterNameMap)); - typeRef.replace(fullyQualifiedReceiverTypeRef); - } - - @NotNull - private static JetType substituteType(@NotNull JetType type, @NotNull JetTypeSubstitution substitution, @NotNull Variance variance) { - switch (variance) { - case INVARIANT: - // for invariant, can replace only when they're equal - if (type.equals(substitution.getForType())) { - return substitution.getByType(); - } - break; - case IN_VARIANCE: - // for contravariant (e.g. function parameter), can replace type with any of its supertypes - if (JetTypeChecker.INSTANCE.isSubtypeOf(type, substitution.getForType())) { - return substitution.getByType(); - } - break; - case OUT_VARIANCE: - // for covariant (e.g. function return value), can replace type with any of its subtypes - if (JetTypeChecker.INSTANCE.isSubtypeOf(substitution.getForType(), type)) { - return substitution.getByType(); - } - break; - } - - List newArguments = new ArrayList(); - List typeParameters = type.getConstructor().getParameters(); - int i = 0; - for (TypeProjection projection : type.getArguments()) { - TypeParameterDescriptor typeParameter = typeParameters.get(i); - JetType newArgument = substituteType(projection.getType(), substitution, typeParameter.getVariance()); - newArguments.add(new TypeProjectionImpl(Variance.INVARIANT, newArgument)); - i++; - } - return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), - type.isNullable(), newArguments, type.getMemberScope()); - } - - private static boolean containsType(JetType outer, JetType inner) { - if (outer.equals(inner)) { - return true; - } - - for (TypeProjection projection : outer.getArguments()) { - if (containsType(projection.getType(), inner)) { - return true; - } - } - - return false; - } - - @NotNull - private static String renderDescriptor( - @NotNull DeclarationDescriptor declarationDescriptor, - @NotNull Map typeParameterNameMap, - boolean fq - ) { - if (declarationDescriptor instanceof TypeParameterDescriptor) { - String replacement = typeParameterNameMap.get(declarationDescriptor); - return replacement == null ? declarationDescriptor.getName().asString() : replacement; - } - else { - return fq ? DescriptorUtils.getFqName(declarationDescriptor).asString() : declarationDescriptor.getName().asString(); - } - } - - private static String renderType( - @NotNull JetType type, - @NotNull Map typeParameterNameMap, - boolean fq - ) { - List projections = type.getArguments(); - DeclarationDescriptor declarationDescriptor = type.getConstructor().getDeclarationDescriptor(); - assert declarationDescriptor != null; - if (projections.isEmpty()) { - return renderDescriptor(declarationDescriptor, typeParameterNameMap, fq); - } - - List arguments = new ArrayList(); - for (TypeProjection projection : projections) { - arguments.add(renderType(projection.getType(), typeParameterNameMap, fq)); - } - return renderDescriptor(declarationDescriptor, typeParameterNameMap, fq) + "<" + StringUtil.join(arguments, ", ") + ">"; - } - - @NotNull - private static String renderTypeShort(@NotNull JetType type, @NotNull Map typeParameterNameMap) { - return renderType(type, typeParameterNameMap, false); - } - - @NotNull - private static String renderTypeLong(@NotNull JetType type, @NotNull Map typeParameterNameMap) { - return renderType(type, typeParameterNameMap, true); - } - - @NotNull - private static TypeParameterDescriptor[] getTypeParameterNamesNotInScope( - @NotNull Collection typeParameters, - @NotNull JetScope scope - ) { - List typeParameterNames = new ArrayList(); - for (TypeParameterDescriptor typeParameter : typeParameters) { - ClassifierDescriptor classifier = scope.getClassifier(typeParameter.getName()); - if (classifier == null || !classifier.equals(typeParameter)) { - typeParameterNames.add(typeParameter); - } - } - return typeParameterNames.toArray(new TypeParameterDescriptor[typeParameterNames.size()]); - } - - @NotNull - private static Set getTypeParametersInType(@NotNull JetType type) { - Set typeParameters = new LinkedHashSet(); - List arguments = type.getArguments(); - if (arguments.isEmpty()) { - ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor(); - if (descriptor instanceof TypeParameterDescriptor) { - typeParameters.add((TypeParameterDescriptor) descriptor); - } - } - else { - for (TypeProjection projection : arguments) { - typeParameters.addAll(getTypeParametersInType(projection.getType())); - } - } - return typeParameters; - } - - /** - * Returns the given name, appended with a number if it is one of the existingNames or already exists in - * scope. For example, given "foo", returns the next non-conflicting name in the list "foo", - * "foo1", "foo2", etc. - */ - @NotNull - private static String getNextAvailableName(@NotNull String name, @NotNull Collection existingNames, @Nullable JetScope scope) { - if (isConflictingName(name, existingNames, scope)) { - int j = 1; - while (isConflictingName(name + j, existingNames, scope)) j++; - name += j; - } - return name; - } - - private static boolean isConflictingName(@NotNull String name, @NotNull Collection existingNames, @Nullable JetScope scope) { - return existingNames.contains(name) || (scope != null && scope.getClassifier(Name.identifier(name)) != null); - } - - @NotNull - private static JetType[] guessTypesForExpression(@NotNull JetExpression expr, @NotNull BindingContext context) { - JetType type = context.get(BindingContext.EXPRESSION_TYPE, expr); - - // if we know the actual type of the expression - if (type != null) { - return new JetType[] {type}; - } - - // expression has an expected type - else if ((type = context.get(BindingContext.EXPECTED_EXPRESSION_TYPE, expr)) != null) { - return new JetType[] {type}; - } - - // expression itself is a type assertion - else if (expr instanceof JetTypeConstraint) { // expression itself is a type assertion - JetTypeConstraint constraint = (JetTypeConstraint) expr; - return new JetType[] {context.get(BindingContext.TYPE, constraint.getBoundTypeReference())}; - } - - // expression is on the left side of a type assertion - else if (expr.getParent() instanceof JetTypeConstraint) { - JetTypeConstraint constraint = (JetTypeConstraint) expr.getParent(); - return new JetType[] {context.get(BindingContext.TYPE, constraint.getBoundTypeReference())}; - } - - // expression is on the lhs of a multi-declaration - else if (expr instanceof JetMultiDeclarationEntry) { - JetMultiDeclarationEntry entry = (JetMultiDeclarationEntry) expr; - JetTypeReference typeRef = entry.getTypeRef(); - if (typeRef != null) { // and has a specified type - return new JetType[] {context.get(BindingContext.TYPE, typeRef)}; - } - return guessTypeForDeclaration(entry, context); // otherwise guess - } - - // expression is a parameter (e.g. declared in a for-loop) - else if (expr instanceof JetParameter) { - JetParameter parameter = (JetParameter) expr; - JetTypeReference typeRef = parameter.getTypeReference(); - if (typeRef != null) { // and has a specified type - return new JetType[] {context.get(BindingContext.TYPE, typeRef)}; - } - return guessTypeForDeclaration(parameter, context); // otherwise guess - } - - // the expression is the RHS of a variable assignment with a specified type - else if (expr.getParent() instanceof JetVariableDeclaration) { - JetVariableDeclaration variable = (JetVariableDeclaration) expr.getParent(); - JetTypeReference typeRef = variable.getTypeRef(); - if (typeRef != null) { // and has a specified type - return new JetType[] {context.get(BindingContext.TYPE, typeRef)}; - } - return guessTypeForDeclaration(variable, context); // otherwise guess, based on LHS - } - - return new JetType[0]; // can't infer anything - } - - private static JetType[] guessTypeForDeclaration(@NotNull JetNamedDeclaration declaration, @NotNull BindingContext context) { - Set expectedTypes = new HashSet(); - SearchScope scope = declaration.getContainingFile().getUseScope(); - for (PsiReference ref : SearchUtils.findAllReferences(declaration, scope)) { - if (ref instanceof JetSimpleNameReference) { - JetSimpleNameReference simpleNameRef = (JetSimpleNameReference) ref; - JetType expectedType = context.get(BindingContext.EXPECTED_EXPRESSION_TYPE, simpleNameRef.getExpression()); - if (expectedType != null) { - expectedTypes.add(expectedType); - } - } - } - if (expectedTypes.isEmpty()) { - return new JetType[0]; // can't guess - } - else { - for (JetType expectedType : expectedTypes) { - if (ErrorUtils.containsErrorType(expectedType)) { - return new JetType[0]; // guessing resulted in an error - } - } - } - JetType type = TypeUtils.intersect(JetTypeChecker.INSTANCE, expectedTypes); - if (type != null) { - return new JetType[] {type}; - } - else { // intersection doesn't exist; let user make an imperfect choice - return expectedTypes.toArray(new JetType[expectedTypes.size()]); - } - } - - @NotNull - public static JetSingleIntentionActionFactory createCreateGetFunctionFromUsageFactory() { - return new JetSingleIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - JetArrayAccessExpression accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetArrayAccessExpression.class); - if (accessExpr == null) return null; - JetExpression arrayExpr = accessExpr.getArrayExpression(); - if (arrayExpr == null) return null; - TypeOrExpressionThereof arrayType = new TypeOrExpressionThereof(arrayExpr, Variance.IN_VARIANCE); - - List parameters = new ArrayList(); - for (JetExpression indexExpr : accessExpr.getIndexExpressions()) { - if (indexExpr == null) return null; - TypeOrExpressionThereof indexType = new TypeOrExpressionThereof(indexExpr, Variance.IN_VARIANCE); - parameters.add(new Parameter(null, indexType)); - } - - TypeOrExpressionThereof returnType = new TypeOrExpressionThereof(accessExpr, Variance.OUT_VARIANCE); - return new CreateFunctionFromUsageFix(accessExpr, arrayType, "get", returnType, parameters); - } - }; - } - - @NotNull - public static JetSingleIntentionActionFactory createCreateSetFunctionFromUsageFactory() { - return new JetSingleIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - JetArrayAccessExpression accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetArrayAccessExpression.class); - if (accessExpr == null) return null; - JetExpression arrayExpr = accessExpr.getArrayExpression(); - if (arrayExpr == null) return null; - TypeOrExpressionThereof arrayType = new TypeOrExpressionThereof(arrayExpr, Variance.IN_VARIANCE); - - List parameters = new ArrayList(); - for (JetExpression indexExpr : accessExpr.getIndexExpressions()) { - if (indexExpr == null) return null; - TypeOrExpressionThereof indexType = new TypeOrExpressionThereof(indexExpr, Variance.IN_VARIANCE); - parameters.add(new Parameter(null, indexType)); - } - - JetBinaryExpression assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetBinaryExpression.class); - if (assignmentExpr == null) return null; - JetExpression rhs = assignmentExpr.getRight(); - if (rhs == null) return null; - TypeOrExpressionThereof valType = new TypeOrExpressionThereof(rhs, Variance.IN_VARIANCE); - parameters.add(new Parameter("value", valType)); - - TypeOrExpressionThereof returnType = - new TypeOrExpressionThereof(KotlinBuiltIns.getInstance().getUnitType(), Variance.OUT_VARIANCE); - return new CreateFunctionFromUsageFix(accessExpr, arrayType, "set", returnType, parameters); - } - }; - } - - @NotNull - public static JetSingleIntentionActionFactory createCreateHasNextFunctionFromUsageFactory() { - return new JetSingleIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - assert diagnostic.getFactory() == Errors.HAS_NEXT_MISSING || - diagnostic.getFactory() == Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE; - @SuppressWarnings("unchecked") - DiagnosticWithParameters1 diagnosticWithParameters = - (DiagnosticWithParameters1) diagnostic; - TypeOrExpressionThereof ownerType = new TypeOrExpressionThereof(diagnosticWithParameters.getA(), Variance.IN_VARIANCE); - - JetForExpression forExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetForExpression.class); - if (forExpr == null) return null; - TypeOrExpressionThereof returnType = - new TypeOrExpressionThereof(KotlinBuiltIns.getInstance().getBooleanType(), Variance.OUT_VARIANCE); - return new CreateFunctionFromUsageFix(forExpr, ownerType, "hasNext", returnType, new ArrayList()); - } - }; - } - - @NotNull - public static JetSingleIntentionActionFactory createCreateNextFunctionFromUsageFactory() { - return new JetSingleIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - assert diagnostic.getFactory() == Errors.NEXT_MISSING || diagnostic.getFactory() == Errors.NEXT_NONE_APPLICABLE; - @SuppressWarnings("unchecked") - DiagnosticWithParameters1 diagnosticWithParameters = - (DiagnosticWithParameters1) diagnostic; - TypeOrExpressionThereof ownerType = new TypeOrExpressionThereof(diagnosticWithParameters.getA(), Variance.IN_VARIANCE); - - JetForExpression forExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetForExpression.class); - if (forExpr == null) return null; - JetExpression variableExpr = forExpr.getLoopParameter(); - if (variableExpr == null) { - variableExpr = forExpr.getMultiParameter(); - if (variableExpr == null) return null; - } - TypeOrExpressionThereof returnType = new TypeOrExpressionThereof(variableExpr, Variance.OUT_VARIANCE); - return new CreateFunctionFromUsageFix(forExpr, ownerType, "next", returnType, new ArrayList()); - } - }; - } - - @NotNull - public static JetSingleIntentionActionFactory createCreateIteratorFunctionFromUsageFactory() { - return new JetSingleIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - PsiFile file = diagnostic.getPsiFile(); - if (!(file instanceof JetFile)) return null; - JetFile jetFile = (JetFile) file; - - JetForExpression forExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetForExpression.class); - if (forExpr == null) return null; - JetExpression iterableExpr = forExpr.getLoopRange(); - if (iterableExpr == null) return null; - JetExpression variableExpr = forExpr.getLoopParameter(); - if (variableExpr == null) { - variableExpr = forExpr.getMultiParameter(); - if (variableExpr == null) return null; - } - TypeOrExpressionThereof iterableType = new TypeOrExpressionThereof(iterableExpr, Variance.IN_VARIANCE); - JetType returnJetType = KotlinBuiltIns.getInstance().getIterator().getDefaultType(); - - BindingContext context = ResolvePackage.getAnalysisResults(jetFile).getBindingContext(); - JetType[] returnJetTypeParameterTypes = guessTypesForExpression(variableExpr, context); - if (returnJetTypeParameterTypes.length != 1) return null; - - TypeProjection returnJetTypeParameterType = new TypeProjectionImpl(returnJetTypeParameterTypes[0]); - List returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType); - returnJetType = new JetTypeImpl(returnJetType.getAnnotations(), returnJetType.getConstructor(), returnJetType.isNullable(), - returnJetTypeArguments, returnJetType.getMemberScope()); - TypeOrExpressionThereof returnType = new TypeOrExpressionThereof(returnJetType, Variance.OUT_VARIANCE); - return new CreateFunctionFromUsageFix(forExpr, iterableType, "iterator", returnType, new ArrayList()); - } - }; - } - - @NotNull - public static JetSingleIntentionActionFactory createCreateComponentFunctionFromUsageFactory() { - return new JetSingleIntentionActionFactory() { - @Nullable - @Override - public IntentionAction createAction(Diagnostic diagnostic) { - assert diagnostic.getFactory() == Errors.COMPONENT_FUNCTION_MISSING; - @SuppressWarnings("unchecked") - DiagnosticWithParameters2 diagnosticWithParameters = - (DiagnosticWithParameters2) diagnostic; - Name name = diagnosticWithParameters.getA(); - Matcher componentNumberMatcher = COMPONENT_FUNCTION_PATTERN.matcher(name.getIdentifier()); - if (!componentNumberMatcher.matches()) return null; - String componentNumberString = componentNumberMatcher.group(1); - int componentNumber = Integer.decode(componentNumberString) - 1; - - JetMultiDeclaration multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, JetMultiDeclaration.class); - TypeOrExpressionThereof ownerType; - if (multiDeclaration == null) { - JetForExpression forExpr = QuickFixUtil.getParentElementOfType(diagnostic, JetForExpression.class); - assert forExpr != null; // if it's not a multi-declaration, must be a multi parameter in a for-loop - multiDeclaration = forExpr.getMultiParameter(); - assert multiDeclaration != null; // for-loop must have a multi-declaration, for same reason as above - ownerType = new TypeOrExpressionThereof(diagnosticWithParameters.getB(), Variance.IN_VARIANCE); - } - else { - JetExpression rhs = multiDeclaration.getInitializer(); - if (rhs == null) return null; - ownerType = new TypeOrExpressionThereof(rhs, Variance.IN_VARIANCE); - } - List entries = multiDeclaration.getEntries(); - - JetMultiDeclarationEntry entry = entries.get(componentNumber); - TypeOrExpressionThereof returnType = new TypeOrExpressionThereof(entry, Variance.OUT_VARIANCE); - - return new CreateFunctionFromUsageFix(multiDeclaration, ownerType, name.getIdentifier(), returnType, - new ArrayList()); - } - }; - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.kt b/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.kt new file mode 100644 index 00000000000..a2c63d32e13 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/CreateFunctionFromUsageFix.kt @@ -0,0 +1,1024 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.codeInsight.navigation.NavigationUtil +import com.intellij.codeInsight.template.* +import com.intellij.codeInsight.template.impl.TemplateImpl +import com.intellij.codeInsight.template.impl.Variable +import com.intellij.ide.fileTemplates.FileTemplate +import com.intellij.ide.fileTemplates.FileTemplateManager +import com.intellij.ide.util.PsiElementListCellRenderer +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.progress.ProcessCanceledException +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.popup.PopupChooserBuilder +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.PsiElement +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.refactoring.psi.SearchUtils +import com.intellij.ui.components.JBList +import com.intellij.util.ArrayUtil +import com.intellij.util.IncorrectOperationException +import org.jetbrains.jet.lang.descriptors.* +import org.jetbrains.jet.lang.diagnostics.Diagnostic +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1 +import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters2 +import org.jetbrains.jet.lang.diagnostics.Errors +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lang.resolve.BindingContextUtils +import org.jetbrains.jet.lang.resolve.DescriptorUtils +import org.jetbrains.jet.lang.resolve.name.Name +import org.jetbrains.jet.lang.resolve.scopes.JetScope +import org.jetbrains.jet.lang.types.* +import org.jetbrains.jet.lang.types.checker.JetTypeChecker +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns +import org.jetbrains.jet.plugin.JetBundle +import org.jetbrains.jet.plugin.caches.resolve +import org.jetbrains.jet.plugin.codeInsight.DescriptorToDeclarationUtil +import org.jetbrains.jet.plugin.codeInsight.ShortenReferences +import org.jetbrains.jet.plugin.presentation.JetClassPresenter +import org.jetbrains.jet.plugin.refactoring.JetNameSuggester +import org.jetbrains.jet.plugin.refactoring.JetNameValidator +import org.jetbrains.jet.plugin.references.JetSimpleNameReference +import javax.swing.* +import java.util.regex.Pattern +import kotlin.properties.Delegates +import java.util.LinkedHashSet +import java.util.Collections +import java.util.HashSet +import java.util.HashMap +import java.util.ArrayList +import java.awt.Component +import java.util.Properties +import org.jetbrains.jet.plugin.caches.resolve.getAnalysisResults +import org.jetbrains.jet.plugin.caches.resolve.getBindingContext + +private val TYPE_PARAMETER_LIST_VARIABLE_NAME = "typeParameterList" +private val TEMPLATE_FROM_USAGE_FUNCTION_BODY = "New Kotlin Function Body.kt" +private val ATTRIBUTE_FUNCTION_NAME = "FUNCTION_NAME" +private val COMPONENT_FUNCTION_PATTERN = Pattern.compile("^component(\\d+)$") + + +/** + * Represents a single choice for a type (e.g. parameter type or return type). + */ +private class TypeCandidate(public val theType: JetType, scope: JetScope? = null) { + public val typeParameters: Array + public var renderedType: String? = null + private set + public var typeParameterNames: Array? = null + private set + + public fun render(typeParameterNameMap: Map) { + renderedType = theType.renderShort(typeParameterNameMap); + typeParameterNames = typeParameters.map { typeParameterNameMap[it]!! }.copyToArray() + } + + { + val typeParametersInType = theType.getTypeParameters() + if (scope == null) { + typeParameters = typeParametersInType.copyToArray() + renderedType = theType.renderShort(Collections.emptyMap()); + } + else { + typeParameters = getTypeParameterNamesNotInScope(typeParametersInType, scope).copyToArray(); + } + } +} + +/** + * Represents an element in the class selection list. + */ +private class ClassCandidate(public val typeCandidate: TypeCandidate, file: JetFile, context: BindingContext) { + public val jetClass: JetClass = DescriptorToDeclarationUtil.getDeclaration( + file, + DescriptorUtils.getClassDescriptorForType(typeCandidate.theType), + context + ) as JetClass +} + +/** + * Renders a ClassCandidate. + */ +private class ClassCandidateListCellRenderer : PsiElementListCellRenderer() { + private val presenter: JetClassPresenter = JetClassPresenter(); + + override fun getElementText(element: JetClass?) = presenter.getPresentation(element!!)?.getPresentableText() + + override fun getContainerText(element: JetClass?, name: String?) = presenter.getPresentation(element!!)?.getLocationString() + + override fun getIconFlags() = 0 + + override fun getListCellRendererComponent(list: JList, value: Any?, index: Int, isSelected: Boolean, cellHasFocus: Boolean): Component? { + return super.getListCellRendererComponent(list, (value as ClassCandidate).jetClass, index, isSelected, cellHasFocus) + } +} + +/** + * Represents a concrete type or a set of types yet to be inferred from an expression. + */ +private fun TypeOrExpressionThereof(expressionOfType: JetExpression, variance: Variance): TypeOrExpressionThereof = + TypeOrExpressionThereof(variance, expressionOfType, null) +private fun TypeOrExpressionThereof(theType: JetType, variance: Variance): TypeOrExpressionThereof = + TypeOrExpressionThereof(variance, null, theType) + +private class TypeOrExpressionThereof(private val variance: Variance, + public val expressionOfType: JetExpression?, + public val theType: JetType?) { + public var typeCandidates: List? = null + private set + + public val possibleNamesFromExpression: Array by Delegates.lazy { + if (isType()) { + ArrayUtil.EMPTY_STRING_ARRAY + } + else { + JetNameSuggester.suggestNamesForExpression( + expressionOfType!!, + JetNameValidator.getEmptyValidator(expressionOfType.getProject()) + ) + } + } + + public fun isType(): Boolean = (theType != null) + + private fun getPossibleTypes(context: BindingContext): List { + val types = ArrayList() + if (theType != null) { + types.add(theType) + if (variance == Variance.IN_VARIANCE) { + types.addAll(TypeUtils.getAllSupertypes(theType)) + } + } + else { + for (theType in expressionOfType!!.guessTypes(context)) { + types.add(theType) + if (variance == Variance.IN_VARIANCE) { + types.addAll(TypeUtils.getAllSupertypes(theType)) + } + } + } + return types + } + + public fun computeTypeCandidates(context: BindingContext) { + typeCandidates = getPossibleTypes(context).map { TypeCandidate(it) } + } + + public fun computeTypeCandidates(context: BindingContext, substitutions: Array, scope: JetScope) { + val types = getPossibleTypes(context).reverse() + + val newTypes = LinkedHashSet(types) + for (substitution in substitutions) { + // each substitution can be applied or not, so we offer all options + val toAdd = newTypes.map { theType -> theType.substitute(substitution, variance) } + // substitution.byType are type arguments, but they cannot already occur in the type before substitution + val toRemove = newTypes.filter { theType -> substitution.byType in theType } + + newTypes.addAll(toAdd) + newTypes.removeAll(toRemove) + } + + if (newTypes.empty) { + newTypes.add(KotlinBuiltIns.getInstance().getAnyType()) + } + + typeCandidates = newTypes.map { TypeCandidate(it, scope) }.reverse() + } + + public fun renderTypeCandidates(typeParameterNameMap: Map) { + typeCandidates!!.forEach { it.render(typeParameterNameMap) } + } +} + +/** + * Encapsulates information about a function parameter that is going to be created. + */ +private class Parameter( + public val theType: TypeOrExpressionThereof, + public val preferredName: String? = null +) + +/** + * Special Expression for parameter names based on its type. + */ +private class ParameterNameExpression( + private val names: Array, + private val parameterTypeToNamesMap: Map>) : Expression() { + { + assert(names all { it.isNotEmpty() }) + } + + override fun calculateResult(context: ExpressionContext?): Result? { + val lookupItems = calculateLookupItems(context)!! + return TextResult(if (lookupItems.isEmpty()) "" else lookupItems.first().getLookupString()) + } + + override fun calculateQuickResult(context: ExpressionContext?) = calculateResult(context) + + override fun calculateLookupItems(context: ExpressionContext?): Array? { + context!! + val names = LinkedHashSet(this.names.toList()) + + // find the parameter list + val project = context.getProject()!! + val offset = context.getStartOffset() + PsiDocumentManager.getInstance(project).commitAllDocuments() + val editor = context.getEditor()!! + val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()) as JetFile + val elementAt = file.findElementAt(offset) + val func = PsiTreeUtil.getParentOfType(elementAt, javaClass()) ?: return array() + val parameterList = func.getValueParameterList()!! + + // add names based on selected type + val parameter = PsiTreeUtil.getParentOfType(elementAt, javaClass()) + if (parameter != null) { + val parameterTypeRef = parameter.getTypeReference() + if (parameterTypeRef != null) { + val suggestedNamesBasedOnType = parameterTypeToNamesMap[parameterTypeRef.getText()] + if (suggestedNamesBasedOnType != null) { + names.addAll(suggestedNamesBasedOnType) + } + } + } + + // remember other parameter names for later use + val parameterNames = parameterList.getParameters().stream().map { jetParameter -> + if (jetParameter == parameter) null else jetParameter.getName() + }.filterNotNullTo(HashSet()) + + // add fallback parameter name + if (names.isEmpty()) { + names.add("arg") + } + + // ensure there are no conflicts + return names.map { name -> + LookupElementBuilder.create(getNextAvailableName(name, parameterNames, null)) + }.copyToArray() + } +} + +/** + * An Expression for type references. + */ +private class TypeExpression(public val theType: TypeOrExpressionThereof) : Expression() { + private val cachedLookupElements: Array = theType.typeCandidates!!.map { + LookupElementBuilder.create(it, it.renderedType!!) + }.copyToArray() + + override fun calculateResult(context: ExpressionContext?): Result { + val lookupItems = calculateLookupItems(context) + return TextResult(if (lookupItems.size == 0) "" else lookupItems[0].getLookupString()) + } + + override fun calculateQuickResult(context: ExpressionContext?) = calculateResult(context) + + override fun calculateLookupItems(context: ExpressionContext?) = cachedLookupElements + + public fun getTypeFromSelection(selection: String): JetType? { + return theType.typeCandidates!!.firstOrNull { it.renderedType == selection }?.theType + } +} + +/** + * A sort-of dummy Expression for parameter lists, to allow us to update the parameter list as the user makes selections. + */ +private class TypeParameterListExpression(private val typeParameterNamesFromReceiverType: Array, + private val parameterTypeToTypeParameterNamesMap: Map>) : Expression() { + + override fun calculateResult(context: ExpressionContext?): Result { + context!! + val project = context.getProject()!! + val offset = context.getStartOffset() + + PsiDocumentManager.getInstance(project).commitAllDocuments() + val editor = context.getEditor()!! + val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument()) as JetFile + val elementAt = file.findElementAt(offset) + val func = PsiTreeUtil.getParentOfType(elementAt, javaClass()) ?: return TextResult("") + val parameters = func.getValueParameters() + + val typeParameterNames = LinkedHashSet() + typeParameterNames.addAll(typeParameterNamesFromReceiverType) + for (parameter in parameters) { + val parameterTypeRef = parameter.getTypeReference() + if (parameterTypeRef != null) { + val typeParameterNamesFromParameter = parameterTypeToTypeParameterNamesMap[parameterTypeRef.getText()] + if (typeParameterNamesFromParameter != null) { + typeParameterNames.addAll(typeParameterNamesFromParameter) + } + } + } + val returnTypeRef = func.getReturnTypeRef() + if (returnTypeRef != null) { + val typeParameterNamesFromReturnType = parameterTypeToTypeParameterNamesMap[returnTypeRef.getText()] + if (typeParameterNamesFromReturnType != null) { + typeParameterNames.addAll(typeParameterNamesFromReturnType) + } + } + + return TextResult(if (typeParameterNames.empty) "" else typeParameterNames.makeString(", ", " <", ">")) + } + + override fun calculateQuickResult(context: ExpressionContext?): Result = calculateResult(context) + + // do not offer the user any choices + override fun calculateLookupItems(context: ExpressionContext?) = array() +} + +private fun JetType.contains(inner: JetType): Boolean { + return this == inner || getArguments().any { inner in it.getType() } +} + +private fun DeclarationDescriptor.render( + typeParameterNameMap: Map, + fq: Boolean +): String = when { + this is TypeParameterDescriptor -> typeParameterNameMap[this] ?: getName().asString() + fq -> DescriptorUtils.getFqName(this).asString() + else -> getName().asString() +} + +private fun JetType.render(typeParameterNameMap: Map, fq: Boolean): String { + val arguments = getArguments().map { it.getType().render(typeParameterNameMap, fq) } + val typeString = getConstructor().getDeclarationDescriptor()!!.render(typeParameterNameMap, fq) + val typeArgumentString = if (arguments.notEmpty) arguments.makeString(", ", "<", ">") else "" + return "$typeString$typeArgumentString" +} + +private fun JetType.renderShort(typeParameterNameMap: Map) = render(typeParameterNameMap, false) +private fun JetType.renderLong(typeParameterNameMap: Map) = render(typeParameterNameMap, true) + +private fun getTypeParameterNamesNotInScope(typeParameters: Collection, scope: JetScope): List { + return typeParameters.filter { typeParameter -> + val classifier = scope.getClassifier(typeParameter.getName()) + classifier == null || classifier != typeParameter + } +} + +private fun JetType.getTypeParameters(): Set { + val typeParameters = LinkedHashSet() + val arguments = getArguments() + if (arguments.empty) { + val descriptor = getConstructor().getDeclarationDescriptor() + if (descriptor is TypeParameterDescriptor) { + typeParameters.add(descriptor as TypeParameterDescriptor) + } + } + else { + arguments.flatMapTo(typeParameters) { projection -> + projection.getType().getTypeParameters() + } + } + return typeParameters +} + +/** + * Returns the given name, appended with a number if it is one of the existingNames or already exists in + * scope. For example, given "foo", returns the next non-conflicting name in the list "foo", + * "foo1", "foo2", etc. + */ +private fun getNextAvailableName(name: String, existingNames: Collection, scope: JetScope?): String { + return if (isConflictingName(name, existingNames, scope)) { + "$name${stream(1) { it + 1 } first { !isConflictingName("$name$it", existingNames, scope) }}" + } + else { + name + } +} + +private fun isConflictingName(name: String, existingNames: Collection, scope: JetScope?): Boolean { + return name in existingNames || scope?.getClassifier(Name.identifier(name)) != null +} + +private fun JetExpression.guessTypes(context: BindingContext): Array { + + // if we know the actual type of the expression + val theType1 = context[BindingContext.EXPRESSION_TYPE, this] + if (theType1 != null) { + return array(theType1) + } + + // expression has an expected type + val theType2 = context[BindingContext.EXPECTED_EXPRESSION_TYPE, this] + if (theType2 != null) { + return array(theType2) + } + + return when { + this is JetTypeConstraint -> { + // expression itself is a type assertion + val constraint = (this as JetTypeConstraint) + array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!) + } + getParent() is JetTypeConstraint -> { + // expression is on the left side of a type assertion + val constraint = (getParent() as JetTypeConstraint) + array(context[BindingContext.TYPE, constraint.getBoundTypeReference()]!!) + } + this is JetMultiDeclarationEntry -> { + // expression is on the lhs of a multi-declaration + val typeRef = getTypeRef() + if (typeRef != null) { + // and has a specified type + array(context[BindingContext.TYPE, typeRef]!!) + } + else { + // otherwise guess + guessType(context) + } + } + this is JetParameter -> { + // expression is a parameter (e.g. declared in a for-loop) + val typeRef = getTypeReference() + if (typeRef != null) { + // and has a specified type + array(context[BindingContext.TYPE, typeRef]!!) + } + else { + // otherwise guess + guessType(context) + } + } + getParent() is JetVariableDeclaration -> { + // the expression is the RHS of a variable assignment with a specified type + val variable = getParent() as JetVariableDeclaration + val typeRef = variable.getTypeRef() + if (typeRef != null) { + // and has a specified type + array(context[BindingContext.TYPE, typeRef]!!) + } + else { + // otherwise guess, based on LHS + variable.guessType(context) + } + } + else -> array() // can't infer anything + } +} + +private fun JetNamedDeclaration.guessType(context: BindingContext): Array { + val scope = getContainingFile()!!.getUseScope() + val expectedTypes = SearchUtils.findAllReferences(this, scope)!!.stream().map { ref -> + if (ref is JetSimpleNameReference) { + context[BindingContext.EXPECTED_EXPRESSION_TYPE, ref.expression] + } + else { + null + } + }.filterNotNullTo(HashSet()) + + if (expectedTypes.isEmpty() || expectedTypes.any { expectedType -> ErrorUtils.containsErrorType(expectedType) }) { + return array() + } + val theType = TypeUtils.intersect(JetTypeChecker.INSTANCE, expectedTypes) + if (theType != null) { + return array(theType) + } + else { + // intersection doesn't exist; let user make an imperfect choice + return expectedTypes.copyToArray() + } +} + +/** + * Encapsulates a single type substitution of a JetType by another JetType. + */ +private class JetTypeSubstitution(public val forType: JetType, public val byType: JetType) + +private fun JetType.substitute(substitution: JetTypeSubstitution, variance: Variance): JetType { + if (when (variance) { + Variance.INVARIANT -> this == substitution.forType + Variance.IN_VARIANCE -> JetTypeChecker.INSTANCE.isSubtypeOf(this, substitution.forType) + Variance.OUT_VARIANCE -> JetTypeChecker.INSTANCE.isSubtypeOf(substitution.forType, this) + }) { + return substitution.byType + } + else { + val newArguments = getArguments().zip(getConstructor().getParameters()).map { pair -> + val (projection, typeParameter) = pair + TypeProjectionImpl(Variance.INVARIANT, projection.getType().substitute(substitution, typeParameter.getVariance())) + } + return JetTypeImpl(getAnnotations(), getConstructor(), isNullable(), newArguments, getMemberScope()) + } +} + +public class CreateFunctionFromUsageFix internal ( + element: PsiElement, + private val ownerType: TypeOrExpressionThereof, + private val functionName: String, + private val returnType: TypeOrExpressionThereof, + private val parameters: List = Collections.emptyList() +) : CreateFromUsageFixBase(element) { + private var isUnit: Boolean = false + private var isExtension: Boolean = false + private var currentFile: JetFile by Delegates.notNull() + private var containingFile: JetFile by Delegates.notNull() + private var currentFileEditor: Editor by Delegates.notNull() + private var containingFileEditor: Editor by Delegates.notNull() + private var currentFileContext: BindingContext by Delegates.notNull() + private var currentFileModule: ModuleDescriptor by Delegates.notNull() + private var ownerClass: JetClass by Delegates.notNull() + private var ownerClassDescriptor: ClassDescriptor by Delegates.notNull() + private var selectedReceiverType: TypeCandidate by Delegates.notNull() + private var typeParameterNameMap: Map by Delegates.notNull() + + override fun getText(): String { + return JetBundle.message("create.function.from.usage", functionName) + } + + override fun invoke(project: Project, editor: Editor?, file: JetFile?) { + currentFile = file!! + currentFileEditor = editor!! + + val exhaust = currentFile.getAnalysisResults() + currentFileContext = exhaust.getBindingContext() + currentFileModule = exhaust.getModuleDescriptor() + + ownerType.computeTypeCandidates(currentFileContext) + val ownerTypeCandidates = ownerType.typeCandidates!! + assert(!ownerTypeCandidates.empty) + + if (ownerTypeCandidates.size == 1 || ApplicationManager.getApplication()!!.isUnitTestMode()) { + selectedReceiverType = ownerTypeCandidates.first!! + addFunctionToSelectedOwner() + } + else { + // class selection + val list = JBList(ownerTypeCandidates.map { ClassCandidate(it, currentFile, currentFileContext) }) + val renderer = ClassCandidateListCellRenderer() + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION) + list.setCellRenderer(renderer) + val builder = PopupChooserBuilder(list) + renderer.installSpeedSearch(builder) + + builder.setTitle(JetBundle.message("choose.target.class.or.trait.title")) + .setItemChoosenCallback { + val selectedCandidate = list.getSelectedValue() as ClassCandidate? + if (selectedCandidate != null) { + selectedReceiverType = selectedCandidate.typeCandidate + CommandProcessor.getInstance().executeCommand(project, { addFunctionToSelectedOwner() }, getText(), null) + } + } + .createPopup() + .showInBestPositionFor(currentFileEditor) + } + } + + private fun addFunctionToSelectedOwner() { + // gather relevant information + ownerClassDescriptor = DescriptorUtils.getClassDescriptorForType(selectedReceiverType.theType) + val receiverType = ownerClassDescriptor.getDefaultType() + val classDeclaration = BindingContextUtils.classDescriptorToDeclaration(currentFileContext, ownerClassDescriptor) + if (classDeclaration is JetClass) { + ownerClass = classDeclaration + isExtension = !ownerClass.isWritable() + } + else { + isExtension = true + } + isUnit = returnType.isType() && KotlinBuiltIns.getInstance().isUnit(returnType.theType!!) + + val scope = if (isExtension) { + currentFileModule.getPackage(currentFile.getPackageFqName())!!.getMemberScope() + } + else { + (ownerClassDescriptor as ClassDescriptorWithResolutionScopes).getScopeForMemberDeclarationResolution() + } + + // figure out type substitutions for type parameters + val classTypeParameters = receiverType.getArguments() + val ownerTypeArguments = selectedReceiverType.theType.getArguments() + assert(ownerTypeArguments.size == classTypeParameters.size) + val substitutions = ownerTypeArguments.zip(classTypeParameters).map { + JetTypeSubstitution(it.first.getType(), it.second.getType()) + }.copyToArray() + parameters.forEach { parameter -> + parameter.theType.computeTypeCandidates(currentFileContext, substitutions, scope) + } + if (!isUnit) { + returnType.computeTypeCandidates(currentFileContext, substitutions, scope) + } + + // now that we have done substitutions, we can throw it away + selectedReceiverType = TypeCandidate(receiverType, scope) + + // figure out type parameter renames to avoid conflicts + typeParameterNameMap = getTypeParameterRenames(scope) + parameters.forEach { parameter -> + parameter.theType.renderTypeCandidates(typeParameterNameMap) + } + if (!isUnit) { + returnType.renderTypeCandidates(typeParameterNameMap) + } + selectedReceiverType.render(typeParameterNameMap) + + ApplicationManager.getApplication()!!.runWriteAction { + val func = createFunctionSkeleton() + buildAndRunTemplate(func) + } + } + + private fun createFunctionSkeleton(): JetNamedFunction { + val project = currentFile.getProject() + val parametersString = parameters.indices.map { i -> "p$i: Any" }.makeString(", ") + val returnTypeString = if (isUnit) "" else ": Any" + if (isExtension) { + // create as extension function + val ownerTypeString = selectedReceiverType.renderedType!! + val func = JetPsiFactory.createFunction(project, "fun $ownerTypeString.$functionName($parametersString)$returnTypeString { }") + containingFile = currentFile + containingFileEditor = currentFileEditor + return currentFile.add(func) as JetNamedFunction + } + else { + // create as regular function + val func = JetPsiFactory.createFunction(project, "fun $functionName($parametersString)$returnTypeString { }") + containingFile = ownerClass.getContainingJetFile() + + NavigationUtil.activateFileWithPsiElement(containingFile) + containingFileEditor = FileEditorManager.getInstance(project)!!.getSelectedTextEditor()!! + + var classBody = ownerClass.getBody() + if (classBody == null) { + classBody = ownerClass.add(JetPsiFactory.createEmptyClassBody(project)) as JetClassBody + ownerClass.addBefore(JetPsiFactory.createWhiteSpace(project), classBody) + } + val rBrace = classBody!!.getRBrace() + //TODO: Assert rbrace not null? It can be if the class isn't closed. + return classBody!!.addBefore(func, rBrace) as JetNamedFunction + } + } + + private fun buildAndRunTemplate(func: JetNamedFunction) { + val project = func.getProject() + val parameterList = func.getValueParameterList()!! + + // build templates + PsiDocumentManager.getInstance(project).commitAllDocuments() + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(containingFileEditor.getDocument()) + + val caretModel = containingFileEditor.getCaretModel() + caretModel.moveToOffset(containingFile.getNode()!!.getStartOffset()) + + val builder = TemplateBuilderImpl(containingFile) + val returnTypeExpression = if (isUnit) null else setupReturnTypeTemplate(builder, func) + val parameterTypeExpressions = setupParameterTypeTemplates(builder, parameterList) + + // 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. + val expression = setupTypeParameterListTemplate(builder, func) + + // the template built by TemplateBuilderImpl is ordered by element position, but we want types to be first, so hack it + val templateImpl = builder.buildInlineTemplate() as TemplateImpl + val variables = templateImpl.getVariables()!! + for (i in 0..(parameters.size - 1)) { + Collections.swap(variables, i * 2, i * 2 + 1) + } + + // fix up the template to include the expression for the type parameter list + variables.add(Variable(TYPE_PARAMETER_LIST_VARIABLE_NAME, expression, expression, false, true)) + + // TODO: Disabled shortening names because it causes some tests fail. Refactor code to use automatic reference shortening + templateImpl.setToShortenLongNames(false) + + // run the template + TemplateManager.getInstance(project).startTemplate(containingFileEditor, templateImpl, object : TemplateEditingAdapter() { + override fun templateFinished(template: Template?, brokenOff: Boolean) { + // file templates + val offset = templateImpl.getSegmentOffset(0) + val newFunc = PsiTreeUtil.findElementOfClassAtOffset(containingFile, offset, javaClass(), false)!! + val typeRefsToShorten = ArrayList() + + ApplicationManager.getApplication()!!.runWriteAction { + // file templates + setupFunctionBody(newFunc) + + // change short type names to fully qualified ones (to be shortened below) + setupTypeReferencesForShortening(newFunc, typeRefsToShorten, parameterTypeExpressions, returnTypeExpression) + ShortenReferences.process(typeRefsToShorten) + } + } + }) + } + + private fun getTypeParameterRenames(scope: JetScope): Map { + val allTypeParametersNotInScope = LinkedHashSet() + + allTypeParametersNotInScope.addAll(selectedReceiverType.typeParameters.toList()) + + parameters.stream() + .flatMap { it.theType.typeCandidates!!.stream() } + .flatMap { it.typeParameters.stream() } + .toCollection(allTypeParametersNotInScope) + + if (!isUnit) { + returnType.typeCandidates!!.stream().flatMapTo(allTypeParametersNotInScope) { it.typeParameters.stream() } + } + + val typeParameterNames = ArrayList() + allTypeParametersNotInScope.mapTo(typeParameterNames) { typeParameter -> + getNextAvailableName(typeParameter.getName().asString(), typeParameterNames, scope) + } + + val typeParameterNameMap = HashMap() + for ((key, value) in allTypeParametersNotInScope.zip(typeParameterNames)) { + typeParameterNameMap[key] = value + } + + return typeParameterNameMap + } + + private fun setupTypeReferencesForShortening( + func: JetNamedFunction, + typeRefsToShorten: MutableList, parameterTypeExpressions: List, + returnTypeExpression: TypeExpression?) { + if (isExtension) { + val receiverTypeRef = JetPsiFactory.createType(func.getProject(), selectedReceiverType.theType.renderLong(typeParameterNameMap)) + replaceWithLongerName(receiverTypeRef, selectedReceiverType.theType) + + val funcReceiverTypeRef = func.getReceiverTypeRef() + if (funcReceiverTypeRef != null) { + typeRefsToShorten.add(funcReceiverTypeRef) + } + } + + if (!isUnit) { + returnTypeExpression!! + val returnTypeRef = func.getReturnTypeRef() + if (returnTypeRef != null) { + val returnType = returnTypeExpression.getTypeFromSelection(returnTypeRef.getText()) + if (returnType != null) { + // user selected a given type + replaceWithLongerName(returnTypeRef, returnType) + typeRefsToShorten.add(func.getReturnTypeRef()!!) + } + } + } + + val valueParameters = func.getValueParameters() + val parameterIndicesToShorten = ArrayList() + assert(valueParameters.size == parameterTypeExpressions.size) + for ((i, parameter) in valueParameters.stream().withIndices()) { + val parameterTypeRef = parameter.getTypeReference() + if (parameterTypeRef != null) { + val parameterType = parameterTypeExpressions[i].getTypeFromSelection(parameterTypeRef.getText()) + if (parameterType != null) { + replaceWithLongerName(parameterTypeRef, parameterType) + parameterIndicesToShorten.add(i) + } + } + } + + val expandedValueParameters = func.getValueParameters() + parameterIndicesToShorten.stream().map { expandedValueParameters[it].getTypeReference() }.filterNotNullTo(typeRefsToShorten) + } + + + private fun setupFunctionBody(func: JetNamedFunction) { + val fileTemplate = FileTemplateManager.getInstance()!!.getCodeTemplate(TEMPLATE_FROM_USAGE_FUNCTION_BODY) + val properties = Properties() + properties.setProperty(FileTemplate.ATTRIBUTE_RETURN_TYPE, if (isUnit) "Unit" else func.getReturnTypeRef()!!.getText()) + properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(ownerClassDescriptor).asString()) + properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, ownerClassDescriptor.getName().asString()) + properties.setProperty(ATTRIBUTE_FUNCTION_NAME, functionName) + + val bodyText = try { + fileTemplate!!.getText(properties) + } + catch (e: ProcessCanceledException) { + throw e + } + catch (e: Exception) { + // TODO: This is dangerous. + // Is there any way to avoid catching all exceptions? + throw IncorrectOperationException("Failed to parse file template", e) + } + + val newBodyExpression = JetPsiFactory.createFunctionBody(func.getProject(), bodyText) + func.getBodyExpression()!!.replace(newBodyExpression) + } + + private fun setupReturnTypeTemplate(builder: TemplateBuilder, func: JetNamedFunction): TypeExpression { + val returnTypeRef = func.getReturnTypeRef()!! + val returnTypeExpression = TypeExpression(returnType) + builder.replaceElement(returnTypeRef, returnTypeExpression) + return returnTypeExpression + } + + private fun setupTypeParameterListTemplate(builder: TemplateBuilderImpl, func: JetNamedFunction): TypeParameterListExpression { + val typeParameterMap = HashMap>() + val receiverTypeParameterNames = selectedReceiverType.typeParameterNames + + parameters.stream().flatMap { it.theType.typeCandidates!!.stream() }.forEach { + typeParameterMap[it.renderedType!!] = it.typeParameterNames!! + } + + if (func.getReturnTypeRef() != null) { + returnType.typeCandidates!!.forEach { + typeParameterMap[it.renderedType!!] = it.typeParameterNames!! + } + } + // ((3, 3) is after "fun") + builder.replaceElement(func, TextRange.create(3, 3), TYPE_PARAMETER_LIST_VARIABLE_NAME, null, false) + return TypeParameterListExpression(receiverTypeParameterNames!!, typeParameterMap) + } + + private fun setupParameterTypeTemplates(builder: TemplateBuilder, parameterList: JetParameterList): List { + val jetParameters = parameterList.getParameters() + assert(jetParameters.size == parameters.size) + val dummyValidator = JetNameValidator.getEmptyValidator(parameterList.getProject()) + + val typeParameters = ArrayList() + for ((parameter, jetParameter) in parameters.zip(jetParameters)) { + val parameterTypeExpression = TypeExpression(parameter.theType) + val parameterTypeRef = jetParameter.getTypeReference()!! + builder.replaceElement(parameterTypeRef, parameterTypeExpression) + + // add parameter name to the template + val possibleNamesFromExpression = parameter.theType.possibleNamesFromExpression + val preferredName = parameter.preferredName + val possibleNames = if (preferredName != null) { + array(preferredName, *possibleNamesFromExpression) + } + else { + possibleNamesFromExpression + } + + // figure out suggested names for each type option + val parameterTypeToNamesMap = HashMap>() + parameter.theType.typeCandidates!!.forEach { typeCandidate -> + val suggestedNames = JetNameSuggester.suggestNamesForType(typeCandidate.theType, dummyValidator) + parameterTypeToNamesMap[typeCandidate.renderedType!!] = suggestedNames + } + + // add expression to builder + val parameterNameExpression = ParameterNameExpression(possibleNames, parameterTypeToNamesMap) + val parameterNameIdentifier = jetParameter.getNameIdentifier()!! + builder.replaceElement(parameterNameIdentifier, parameterNameExpression) + + typeParameters.add(parameterTypeExpression) + } + return typeParameters + } + + private fun replaceWithLongerName(typeRef: JetTypeReference, theType: JetType) { + val project = typeRef.getProject() + val fullyQualifiedReceiverTypeRef = JetPsiFactory.createType(project, theType.renderLong(typeParameterNameMap)) + typeRef.replace(fullyQualifiedReceiverTypeRef) + } + + class object { + public fun createCreateGetFunctionFromUsageFactory(): JetSingleIntentionActionFactory { + return object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic?): IntentionAction? { + val accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val arrayExpr = accessExpr.getArrayExpression() ?: return null + val arrayType = TypeOrExpressionThereof(arrayExpr, Variance.IN_VARIANCE) + + val parameters = accessExpr.getIndexExpressions().map { + Parameter(TypeOrExpressionThereof(it, Variance.IN_VARIANCE)) + } + + val returnType = TypeOrExpressionThereof(accessExpr, Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(accessExpr, arrayType, "get", returnType, parameters) + } + } + } + + public fun createCreateSetFunctionFromUsageFactory(): JetSingleIntentionActionFactory { + return object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic?): IntentionAction? { + val accessExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val arrayExpr = accessExpr.getArrayExpression() ?: return null + val arrayType = TypeOrExpressionThereof(arrayExpr, Variance.IN_VARIANCE) + + val parameters = accessExpr.getIndexExpressions().mapTo(ArrayList()) { + Parameter(TypeOrExpressionThereof(it, Variance.IN_VARIANCE)) + } + + val assignmentExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val rhs = assignmentExpr.getRight() ?: return null + val valType = TypeOrExpressionThereof(rhs, Variance.IN_VARIANCE) + parameters.add(Parameter(valType, "value")) + + val returnType = TypeOrExpressionThereof(KotlinBuiltIns.getInstance().getUnitType(), Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(accessExpr, arrayType, "set", returnType, parameters) + } + } + } + + public fun createCreateHasNextFunctionFromUsageFactory(): JetSingleIntentionActionFactory { + return object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic?): IntentionAction? { + assert(diagnostic!!.getFactory() == Errors.HAS_NEXT_MISSING || diagnostic.getFactory() == Errors.HAS_NEXT_FUNCTION_NONE_APPLICABLE) + [suppress("UNCHECKED_CAST")] + val diagnosticWithParameters = diagnostic as DiagnosticWithParameters1 + val ownerType = TypeOrExpressionThereof(diagnosticWithParameters.getA(), Variance.IN_VARIANCE) + + val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val returnType = TypeOrExpressionThereof(KotlinBuiltIns.getInstance().getBooleanType(), Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(forExpr, ownerType, "hasNext", returnType) + } + } + } + + public fun createCreateNextFunctionFromUsageFactory(): JetSingleIntentionActionFactory { + return object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic?): IntentionAction? { + assert(diagnostic!!.getFactory() == Errors.NEXT_MISSING || diagnostic.getFactory() == Errors.NEXT_NONE_APPLICABLE) + [suppress("UNCHECKED_CAST")] + val diagnosticWithParameters = diagnostic as DiagnosticWithParameters1 + val ownerType = TypeOrExpressionThereof(diagnosticWithParameters.getA(), Variance.IN_VARIANCE) + + val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression + val returnType = TypeOrExpressionThereof(variableExpr, Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(forExpr, ownerType, "next", returnType) + } + } + } + + public fun createCreateIteratorFunctionFromUsageFactory(): JetSingleIntentionActionFactory { + return object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic?): IntentionAction? { + val file = diagnostic!!.getPsiFile() as? JetFile ?: return null + val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) ?: return null + val iterableExpr = forExpr.getLoopRange() ?: return null + val variableExpr: JetExpression = ((forExpr.getLoopParameter() ?: forExpr.getMultiParameter()) ?: return null) as JetExpression + val iterableType = TypeOrExpressionThereof(iterableExpr, Variance.IN_VARIANCE) + val returnJetType = KotlinBuiltIns.getInstance().getIterator().getDefaultType() + + val context = file.getBindingContext() + val returnJetTypeParameterTypes = variableExpr.guessTypes(context) + if (returnJetTypeParameterTypes.size != 1) return null + + val returnJetTypeParameterType = TypeProjectionImpl(returnJetTypeParameterTypes[0]) + val returnJetTypeArguments = Collections.singletonList(returnJetTypeParameterType) + val newReturnJetType = JetTypeImpl(returnJetType.getAnnotations(), returnJetType.getConstructor(), returnJetType.isNullable(), returnJetTypeArguments, returnJetType.getMemberScope()) + val returnType = TypeOrExpressionThereof(newReturnJetType, Variance.OUT_VARIANCE) + return CreateFunctionFromUsageFix(forExpr, iterableType, "iterator", returnType) + } + } + } + + public fun createCreateComponentFunctionFromUsageFactory(): JetSingleIntentionActionFactory { + return object : JetSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic?): IntentionAction? { + assert(diagnostic!!.getFactory() == Errors.COMPONENT_FUNCTION_MISSING) + [suppress("UNCHECKED_CAST")] + val diagnosticWithParameters = (diagnostic as DiagnosticWithParameters2) + val name = diagnosticWithParameters.getA() + val componentNumberMatcher = COMPONENT_FUNCTION_PATTERN.matcher(name.getIdentifier()) + if (!componentNumberMatcher.matches()) return null + val componentNumberString = componentNumberMatcher.group(1)!! + val componentNumber = Integer.decode(componentNumberString)!! - 1 + + var multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, javaClass()) + val ownerType = if (multiDeclaration == null) { + val forExpr = QuickFixUtil.getParentElementOfType(diagnostic, javaClass())!! + multiDeclaration = forExpr.getMultiParameter()!! + TypeOrExpressionThereof(diagnosticWithParameters.getB(), Variance.IN_VARIANCE) + } + else { + val rhs = multiDeclaration!!.getInitializer() ?: return null + TypeOrExpressionThereof(rhs, Variance.IN_VARIANCE) + } + val entries = multiDeclaration!!.getEntries() + + val entry = entries[componentNumber] + val returnType = TypeOrExpressionThereof(entry, Variance.OUT_VARIANCE) + + return CreateFunctionFromUsageFix(multiDeclaration!!, ownerType, name.getIdentifier(), returnType) + } + } + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index f8a48def99b..a43daabb66e 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -250,15 +250,15 @@ public class QuickFixes { factories.put(MANY_CLASSES_IN_SUPERTYPE_LIST, RemoveSupertypeFix.createFactory()); - factories.put(NO_GET_METHOD, CreateFunctionFromUsageFix.createCreateGetFunctionFromUsageFactory()); - factories.put(NO_SET_METHOD, CreateFunctionFromUsageFix.createCreateSetFunctionFromUsageFactory()); - JetSingleIntentionActionFactory createHasNextFromUsageFactory = CreateFunctionFromUsageFix.createCreateHasNextFunctionFromUsageFactory(); + factories.put(NO_GET_METHOD, CreateFunctionFromUsageFix.object$.createCreateGetFunctionFromUsageFactory()); + factories.put(NO_SET_METHOD, CreateFunctionFromUsageFix.object$.createCreateSetFunctionFromUsageFactory()); + JetSingleIntentionActionFactory createHasNextFromUsageFactory = CreateFunctionFromUsageFix.object$.createCreateHasNextFunctionFromUsageFactory(); factories.put(HAS_NEXT_MISSING, createHasNextFromUsageFactory); factories.put(HAS_NEXT_FUNCTION_NONE_APPLICABLE, createHasNextFromUsageFactory); - JetSingleIntentionActionFactory createNextFromUsageFactory = CreateFunctionFromUsageFix.createCreateNextFunctionFromUsageFactory(); + JetSingleIntentionActionFactory createNextFromUsageFactory = CreateFunctionFromUsageFix.object$.createCreateNextFunctionFromUsageFactory(); factories.put(NEXT_MISSING, createNextFromUsageFactory); factories.put(NEXT_NONE_APPLICABLE, createNextFromUsageFactory); - factories.put(ITERATOR_MISSING, CreateFunctionFromUsageFix.createCreateIteratorFunctionFromUsageFactory()); - factories.put(COMPONENT_FUNCTION_MISSING, CreateFunctionFromUsageFix.createCreateComponentFunctionFromUsageFactory()); + factories.put(ITERATOR_MISSING, CreateFunctionFromUsageFix.object$.createCreateIteratorFunctionFromUsageFactory()); + factories.put(COMPONENT_FUNCTION_MISSING, CreateFunctionFromUsageFix.object$.createCreateComponentFunctionFromUsageFactory()); } }