Refactored "Change to constructor invocation" and new "Add constructor parameters and use them" quickfixes into one factory, making the first one always available
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
#quick fix messages
|
||||
add.function.body=Add function body
|
||||
change.to.constructor.invocation=Change to constructor invocation
|
||||
add.return.type=Add return type declaration
|
||||
change.accessor.type=Change accessor type
|
||||
change.getter.type=Change getter type to {0}
|
||||
|
||||
+2
-2
@@ -28,8 +28,8 @@ public abstract class JetIntentionActionsFactory {
|
||||
|
||||
public fun createActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
if (diagnostic.getPsiElement().getContainingFile() is JetCodeFragment && !isApplicableForCodeFragment()) {
|
||||
return Collections.emptyList()
|
||||
return emptyList()
|
||||
}
|
||||
return doCreateActions(diagnostic) ?: Collections.emptyList()
|
||||
return doCreateActions(diagnostic) ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.ArrayList
|
||||
|
||||
public class AddConstructorParametersFromSuperFix private(
|
||||
element: JetDelegatorToSuperClass,
|
||||
val classDeclaration: JetClass,
|
||||
val superConstructor: ConstructorDescriptor
|
||||
) : JetIntentionAction<JetDelegatorToSuperClass>(element) {
|
||||
|
||||
override fun getFamilyName() = "Add constructor parameters from superclass"
|
||||
|
||||
override fun getText() = "Add constructor parameters and use them"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
val factory = JetPsiFactory(project)
|
||||
val renderer = IdeDescriptorRenderers.SOURCE_CODE
|
||||
|
||||
val superParameters = superConstructor.getValueParameters()
|
||||
val parameterNames = ArrayList<String>()
|
||||
val typeRefsToShorten = ArrayList<JetTypeReference>()
|
||||
if (!superParameters.isEmpty()) {
|
||||
val parameterList = classDeclaration.getOrCreatePrimaryConstructorParameterList()
|
||||
for (parameter in superParameters) {
|
||||
//TODO: what if type is error?
|
||||
val name = renderer.renderName(parameter.getName())
|
||||
val parameterText = name + ":" + renderer.renderType(parameter.getType())
|
||||
val newParameter = parameterList.addParameter(factory.createParameter(parameterText))
|
||||
typeRefsToShorten.add(newParameter.getTypeReference())
|
||||
parameterNames.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
val delegatorCall = factory.createDelegatorToSuperCall(element.getText() + "(" + parameterNames.joinToString(",") + ")")
|
||||
element.replace(delegatorCall)
|
||||
|
||||
ShortenReferences.DEFAULT.process(typeRefsToShorten)
|
||||
}
|
||||
|
||||
companion object : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): JetIntentionAction<JetDelegatorToSuperClass>? {
|
||||
val delegator = diagnostic.getPsiElement() as JetDelegatorToSuperClass
|
||||
val classDeclaration = delegator.getParent().getParent() as? JetClass ?: return null
|
||||
|
||||
val typeRef = delegator.getTypeReference() ?: return null
|
||||
val type = typeRef.analyze()[BindingContext.TYPE, typeRef] ?: return null
|
||||
if (type.isError()) return null
|
||||
|
||||
val superClass = (type.getConstructor().getDeclarationDescriptor() as? ClassDescriptor) ?: return null
|
||||
val classDescriptor = delegator.getResolutionFacade().resolveToDescriptor(classDeclaration) as ClassDescriptor
|
||||
val constructors = superClass.getConstructors().filter { it.isVisible(classDescriptor) }
|
||||
val constructorToUse = constructors.singleOrNull()
|
||||
?: constructors.singleOrNull { it.isPrimary() } //TODO: should we select it automatically in this case?
|
||||
?: return null
|
||||
//TODO: choose among multiple
|
||||
if (constructorToUse.getValueParameters().isEmpty()) return null
|
||||
|
||||
val superType = classDescriptor.getTypeConstructor().getSupertypes().first { it.getConstructor().getDeclarationDescriptor() == superClass }
|
||||
val typeArgsMap = superClass.getTypeConstructor().getParameters().zip(superType.getArguments()).toMap()
|
||||
val substitutor = TypeUtils.makeSubstitutorForTypeParametersMap(typeArgsMap)
|
||||
val substitutedConstructor = constructorToUse.substitute(substitutor) as ConstructorDescriptor
|
||||
|
||||
return AddConstructorParametersFromSuperFix(delegator, classDeclaration, substitutedConstructor)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.quickfix;
|
||||
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.idea.JetBundle;
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolvePackage;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.psi.PsiPackage.JetPsiFactory;
|
||||
|
||||
public class ChangeToConstructorInvocationFix extends JetIntentionAction<JetDelegatorToSuperClass> {
|
||||
|
||||
public ChangeToConstructorInvocationFix(@NotNull JetDelegatorToSuperClass element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getText() {
|
||||
return JetBundle.message("change.to.constructor.invocation");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return JetBundle.message("change.to.constructor.invocation");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
if (!super.isAvailable(project, editor, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JetTypeReference typeReference = element.getTypeReference();
|
||||
BindingContext context = ResolvePackage.analyzeFully(typeReference);
|
||||
JetType supertype = context.get(BindingContext.TYPE, typeReference);
|
||||
if (supertype == null) return false;
|
||||
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
|
||||
if (classDescriptor == null) return false;
|
||||
for (ConstructorDescriptor constructor : classDescriptor.getConstructors()) {
|
||||
boolean needsParametersPassed = false;
|
||||
for (ValueParameterDescriptor parameter : constructor.getValueParameters()) {
|
||||
needsParametersPassed |= !parameter.hasDefaultValue() && parameter.getVarargElementType() == null;
|
||||
}
|
||||
if (!needsParametersPassed) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
|
||||
JetDelegatorToSuperClass delegator = (JetDelegatorToSuperClass) element.copy();
|
||||
JetClass aClass = JetPsiFactory(file).createClass("class A : " + delegator.getText() + "()");
|
||||
List<JetDelegationSpecifier> delegationSpecifiers = aClass.getDelegationSpecifiers();
|
||||
assert delegationSpecifiers.size() == 1;
|
||||
JetDelegationSpecifier specifier = delegationSpecifiers.iterator().next();
|
||||
element.replace(specifier);
|
||||
}
|
||||
|
||||
public static JetSingleIntentionActionFactory createFactory() {
|
||||
return new JetSingleIntentionActionFactory() {
|
||||
@Override
|
||||
public JetIntentionAction<JetDelegatorToSuperClass> createAction(Diagnostic diagnostic) {
|
||||
if (diagnostic.getPsiElement() instanceof JetDelegatorToSuperClass) {
|
||||
return new ChangeToConstructorInvocationFix((JetDelegatorToSuperClass) diagnostic.getPsiElement());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public class QuickFixRegistrar {
|
||||
JetSingleIntentionActionFactory removeImportFixFactory = RemovePsiElementSimpleFix.createRemoveImportFactory();
|
||||
QuickFixes.factories.put(CONFLICTING_IMPORT, removeImportFixFactory);
|
||||
|
||||
QuickFixes.factories.put(SUPERTYPE_NOT_INITIALIZED, ChangeToConstructorInvocationFix.createFactory());
|
||||
QuickFixes.factories.put(SUPERTYPE_NOT_INITIALIZED, SuperClassNotInitialized.INSTANCE$);
|
||||
QuickFixes.factories.put(FUNCTION_CALL_EXPECTED, ChangeToFunctionInvocationFix.createFactory());
|
||||
|
||||
QuickFixes.factories.put(CANNOT_CHANGE_ACCESS_PRIVILEGE, ChangeVisibilityModifierFix.createFactory());
|
||||
@@ -325,7 +325,5 @@ public class QuickFixRegistrar {
|
||||
|
||||
QuickFixes.factories.put(DEPRECATED_ANNOTATION_SYNTAX, DeprecatedAnnotationSyntaxFix.Companion);
|
||||
QuickFixes.factories.put(DEPRECATED_ANNOTATION_SYNTAX, DeprecatedAnnotationSyntaxFix.Companion.createWholeProjectFixFactory());
|
||||
|
||||
QuickFixes.factories.put(SUPERTYPE_NOT_INITIALIZED, AddConstructorParametersFromSuperFix.Companion);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.IncorrectOperationException
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.core.isVisible
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.replaced
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import java.util.ArrayList
|
||||
|
||||
public object SuperClassNotInitialized : JetIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>? {
|
||||
val delegator = diagnostic.getPsiElement() as JetDelegatorToSuperClass
|
||||
val classOrObjectDeclaration = delegator.getParent().getParent() as? JetClassOrObject ?: return null
|
||||
|
||||
val typeRef = delegator.getTypeReference() ?: return null
|
||||
val type = typeRef.analyze()[BindingContext.TYPE, typeRef] ?: return null
|
||||
if (type.isError()) return null
|
||||
|
||||
val superClass = (type.getConstructor().getDeclarationDescriptor() as? ClassDescriptor) ?: return null
|
||||
val classDescriptor = delegator.getResolutionFacade().resolveToDescriptor(classOrObjectDeclaration) as ClassDescriptor
|
||||
val constructors = superClass.getConstructors().filter { it.isVisible(classDescriptor) }
|
||||
|
||||
val fixes = ArrayList<IntentionAction>()
|
||||
|
||||
fixes.add(AddParenthesisFix(delegator, putCaretIntoParenthesis = constructors.singleOrNull()?.getValueParameters()?.isNotEmpty() ?: true))
|
||||
|
||||
if (classOrObjectDeclaration is JetClass) {
|
||||
val constructorToUse = constructors.singleOrNull()
|
||||
?: constructors.singleOrNull { it.isPrimary() } //TODO: should we select it automatically in this case?
|
||||
//TODO: multiple
|
||||
if (constructorToUse != null && constructorToUse.getValueParameters().isNotEmpty()) {
|
||||
val superType = classDescriptor.getTypeConstructor().getSupertypes().first { it.getConstructor().getDeclarationDescriptor() == superClass }
|
||||
val typeArgsMap = superClass.getTypeConstructor().getParameters().zip(superType.getArguments()).toMap()
|
||||
val substitutor = TypeUtils.makeSubstitutorForTypeParametersMap(typeArgsMap)
|
||||
val substitutedConstructor = constructorToUse.substitute(substitutor) as ConstructorDescriptor
|
||||
fixes.add(AddParametersFix(delegator, classOrObjectDeclaration, substitutedConstructor))
|
||||
}
|
||||
}
|
||||
|
||||
return fixes
|
||||
}
|
||||
|
||||
private class AddParenthesisFix(
|
||||
element: JetDelegatorToSuperClass,
|
||||
val putCaretIntoParenthesis: Boolean
|
||||
) : JetIntentionAction<JetDelegatorToSuperClass>(element) {
|
||||
|
||||
override fun getFamilyName() = "Change to constructor invocation" //TODO?
|
||||
|
||||
override fun getText() = getFamilyName()
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
val newSpecifier = element.replaced(JetPsiFactory(project).createDelegatorToSuperCall(element.getText() + "()"))
|
||||
|
||||
if (putCaretIntoParenthesis) {
|
||||
editor?.moveCaret(newSpecifier.getValueArgumentList()!!.getLeftParenthesis()!!.getTextRange().getEndOffset())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AddParametersFix(
|
||||
element: JetDelegatorToSuperClass,
|
||||
val classDeclaration: JetClass,
|
||||
val superConstructor: ConstructorDescriptor
|
||||
) : JetIntentionAction<JetDelegatorToSuperClass>(element) {
|
||||
|
||||
override fun getFamilyName() = "Add constructor parameters from superclass"
|
||||
|
||||
override fun getText() = "Add constructor parameters and use them"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||
val factory = JetPsiFactory(project)
|
||||
val renderer = IdeDescriptorRenderers.SOURCE_CODE
|
||||
|
||||
val superParameters = superConstructor.getValueParameters()
|
||||
val parameterNames = ArrayList<String>()
|
||||
val typeRefsToShorten = ArrayList<JetTypeReference>()
|
||||
if (!superParameters.isEmpty()) {
|
||||
val parameterList = classDeclaration.getOrCreatePrimaryConstructorParameterList()
|
||||
for (parameter in superParameters) {
|
||||
//TODO: what if type is error?
|
||||
val name = renderer.renderName(parameter.getName())
|
||||
val parameterText = name + ":" + renderer.renderType(parameter.getType())
|
||||
val newParameter = parameterList.addParameter(factory.createParameter(parameterText))
|
||||
typeRefsToShorten.add(newParameter.getTypeReference())
|
||||
parameterNames.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
val delegatorCall = factory.createDelegatorToSuperCall(element.getText() + "(" + parameterNames.joinToString(",") + ")")
|
||||
element.replace(delegatorCall)
|
||||
|
||||
ShortenReferences.DEFAULT.process(typeRefsToShorten)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// "Add constructor parameters and use them" "false"
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.SuperClassNotInitialized$AddParametersFix" "false"
|
||||
// ACTION: Change to constructor invocation
|
||||
// ERROR: This type has a constructor, and thus must be initialized here
|
||||
open class Base
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.ChangeToConstructorInvocationFix" "false"
|
||||
// ERROR: This type has a constructor, and thus must be initialized here
|
||||
// "Change to constructor invocation" "true"
|
||||
// ERROR: No value passed for parameter x
|
||||
open class A(x : Int) {}
|
||||
class B : A<caret> {}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Change to constructor invocation" "true"
|
||||
// ERROR: No value passed for parameter x
|
||||
open class A(x : Int) {}
|
||||
class B : A(<caret>) {}
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// "Change to constructor invocation" "true"
|
||||
open class A(x : Int = 42, vararg y : Int) {}
|
||||
class B() : A<caret>() {}
|
||||
class B() : A(<caret>) {}
|
||||
|
||||
Reference in New Issue
Block a user